Commit 133f9e6b authored by zhangwenshuai's avatar zhangwenshuai

增加分组全选、展开

parent fe9b0f1d
...@@ -76,15 +76,42 @@ ...@@ -76,15 +76,42 @@
.groupLevel { .groupLevel {
position: absolute; position: absolute;
left: 0; left: 0;
width: 100%; min-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
font-size: @textFontGen; font-size: @textFontGen;
height: 40px; height: 40px;
line-height: 40px;
color: @textPrimaryColor; color: @textPrimaryColor;
z-index: 5; z-index: 5;
.groupContainer{
display: flex;
align-items: center;
height: 100%;
.groupCheck{
width: 16px;
margin-right: @marginSm;
}
.groupExpand{
width: 16px;
margin-right: @marginSm;
cursor: pointer;
}
.groupContent{
flex: 1;
overflow: hidden;
display: flex;
flex-direction: column;
justify-content: center;
font-size: @textFontSm;
.groupText{
color: @textPrimaryColor;
overflow: hidden;
text-overflow: ellipsis;
}
.groupCount{
color: @textSupplyColor;
}
}
}
} }
} }
......
...@@ -2,6 +2,7 @@ import React, { useState, useRef } from 'react'; ...@@ -2,6 +2,7 @@ import React, { useState, useRef } from 'react';
import { Checkbox, message, Popover } from 'antd'; import { Checkbox, message, Popover } from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import _ from 'lodash'; import _ from 'lodash';
import memoizeOne from 'memoize-one';
import { config } from './base/config'; import { config } from './base/config';
import { getFormat, setFormat } from './base'; import { getFormat, setFormat } from './base';
import s from './Cell.less'; import s from './Cell.less';
...@@ -11,7 +12,18 @@ import expandIcon from '../assets/extend.png'; ...@@ -11,7 +12,18 @@ import expandIcon from '../assets/extend.png';
import { transferAttr } from './base/_utils/transferAttr'; import { transferAttr } from './base/_utils/transferAttr';
import { emptyModel } from './base/_utils/setFormatter'; import { emptyModel } from './base/_utils/setFormatter';
import { getGroupLevel } from '../utils/memCols'; import { getGroupLevel } from '../utils/memCols';
import IconFont from "@/submodule/components/IconFont/IconFont";
// 获取数据列表的id
const getArrIds = (arr: any) => {
if (!Array.isArray(arr)) {
return [];
}
return arr.map((item: any) => {
return item.id || item;
});
};
export const memoSelected = memoizeOne(getArrIds);
enum EDIT_STATUS { enum EDIT_STATUS {
'FREE', // 空闲 'FREE', // 空闲
'EDITING', // 编辑中 'EDITING', // 编辑中
...@@ -40,6 +52,8 @@ const Cell = (props: CellProps) => { ...@@ -40,6 +52,8 @@ const Cell = (props: CellProps) => {
maxPopHeight, maxPopHeight,
renderFirstLeft, renderFirstLeft,
position, position,
toggleGroup,
dataSource,
} = props; } = props;
const { const {
columnType, columnType,
...@@ -51,16 +65,18 @@ const Cell = (props: CellProps) => { ...@@ -51,16 +65,18 @@ const Cell = (props: CellProps) => {
readOnlyFlag, readOnlyFlag,
columnAttrObj, columnAttrObj,
} = columnConfig; } = columnConfig;
const { selectedRows } = rowSelection || {};
const selectIds = memoSelected(selectedRows);
const cellUnit = useRef(null); const cellUnit = useRef(null);
const [status, setStatus] = useState('detail'); const [status, setStatus] = useState('detail');
// 重置回详情状态
const resetEditStatus = () => { const resetEditStatus = () => {
setStatus('detail'); setStatus('detail');
if (typeof onEmitMsg === 'function') { if (typeof onEmitMsg === 'function') {
onEmitMsg({ status: EDIT_STATUS.FREE }); onEmitMsg({ status: EDIT_STATUS.FREE });
} }
}; };
// 进入编辑状态
const turnIntoEditStatus = (data: any) => { const turnIntoEditStatus = (data: any) => {
setStatus('edit'); setStatus('edit');
if (typeof onEmitMsg === 'function') { if (typeof onEmitMsg === 'function') {
...@@ -129,6 +145,80 @@ const Cell = (props: CellProps) => { ...@@ -129,6 +145,80 @@ const Cell = (props: CellProps) => {
dom.classList.remove(s.hover); dom.classList.remove(s.hover);
}); });
}; };
// 获取当前分组是否全部选中
const getGroupChecked = (level = 1) => {
const children = record[`group${level}Children`];
if (!children) {
return false;
}
for (let i = 0; i < children.length; i++) {
if (!selectIds.includes(children[i])) {
return false;
}
}
return true;
};
// 获取当前分组是否全部展开
const getGroupExpanded = (level = 1) => {
// 获取当前分组的数据id
const children = record[`group${level}Children`];
if (!children) {
return true;
}
for (let i = 0; i < children.length; i++) {
const item=dataSource.find(temp=>temp.id===children[i]);
if(item && !item.hidden){
return true;
}
}
return false;
};
// 切换当前分组全选/反选
const onToggleGroup=(level = 1) => {
const checked = getGroupChecked(level);
const { onChange } = rowSelection;
const children = record[`group${level}Children`];
if (typeof onChange === 'function') {
let data = [];
if (checked) {
data = selectIds.filter((s:number) => {
return !children.includes(s);
});
} else {
data = children.filter((s:number) => {
return !selectIds.includes(s);
});
data = data.concat(selectIds);
}
onChange(data);
}
};
// 切换当前分组展开/收起
const onToggleGroupClose = (level:number = 1) => {
const children = record[`group${level}Children`];
if (typeof toggleGroup === 'function') {
const flag = getGroupExpanded(level);
toggleGroup(children,flag);
}
};
// 获取当前行在所选列表中的index
const getCheckedIndex = () => {
return selectIds.findIndex((item: any) => {
return item === record.id;
});
};
const onToggle = (index: number) => {
const { selectedRows, onChange } = rowSelection;
if (typeof onChange === 'function') {
const data = _.cloneDeep(selectedRows);
if (index > -1) {
data.splice(index, 1);
} else {
data.push(record);
}
onChange(data);
}
};
const renderFirst = () => { const renderFirst = () => {
const { current = 1, pageSize = 20 } = paginationConfig || {}; const { current = 1, pageSize = 20 } = paginationConfig || {};
...@@ -139,36 +229,11 @@ const Cell = (props: CellProps) => { ...@@ -139,36 +229,11 @@ const Cell = (props: CellProps) => {
} }
return (current - 1) * pageSize + rowIndex + 1; return (current - 1) * pageSize + rowIndex + 1;
}; };
// 获取当前行在所选列表中的index
const getCheckedIndex = () => {
if (!rowSelection) {
return -1;
}
const { selectedRows } = rowSelection;
const index =
selectedRows &&
selectedRows.findIndex((item: any) => {
return item.id === record.id;
});
return index;
};
// 构造行复选框 // 构造行复选框
const getCheckbox = () => { const getCheckbox = () => {
const { selectedRows, onChange } = rowSelection;
const index = getCheckedIndex(); const index = getCheckedIndex();
const checked = index > -1; return <Checkbox checked={index > -1} onClick={onToggle.bind(null, index)} />;
const onToggle = () => {
if (typeof onChange === 'function') {
const data = _.cloneDeep(selectedRows);
if (checked) {
data.splice(index, 1);
} else {
data.push(record);
}
onChange(data);
}
};
return <Checkbox checked={checked} onClick={onToggle} />;
}; };
return ( return (
<div className={s.firstArea}> <div className={s.firstArea}>
...@@ -424,12 +489,27 @@ const Cell = (props: CellProps) => { ...@@ -424,12 +489,27 @@ const Cell = (props: CellProps) => {
top: 0, top: 0,
paddingLeft: '16px', paddingLeft: '16px',
background: groupLevel === 3 ? '#EEEEEE' : groupLevel === 2 ? '#EDEDED' : '#F7F9FA', background: groupLevel === 3 ? '#EEEEEE' : groupLevel === 2 ? '#EDEDED' : '#F7F9FA',
zIndex: columnIndex === 0 ? 6 : 5,
}} }}
> >
{columnIndex === 0 && {columnIndex === 0 && position !== 'right' && record.groupConfig[0] && (
position !== 'right' && <div className={s.groupContainer}>
record.groupConfig[0] && <Checkbox
`${record.groupConfig[0].colChsName}:${record.groupTextArr[0]}`} className={s.groupCheck}
checked={getGroupChecked(1)}
onClick={onToggleGroup.bind(null, 1)}
/>
<div className={s.groupExpand} onClick={onToggleGroupClose.bind(null, 1)}>
<IconFont type={getGroupExpanded(1) ? "iconxiala1" : "iconzirenwujinru"} />
</div>
<div className={s.groupContent}>
<span
className={s.groupText}
>{`${record.groupConfig[0].colChsName}:${record.groupTextArr[0]}`}</span>
<span className={s.groupCount}>{`共:${record.group1Children.length}条`}</span>
</div>
</div>
)}
</div> </div>
)} )}
{record.classList && record.classList[1] && ( {record.classList && record.classList[1] && (
...@@ -439,12 +519,27 @@ const Cell = (props: CellProps) => { ...@@ -439,12 +519,27 @@ const Cell = (props: CellProps) => {
top: record.classList[0] ? 40 : 0, top: record.classList[0] ? 40 : 0,
paddingLeft: '32px', paddingLeft: '32px',
background: groupLevel === 3 ? '#F5F5F5' : '#F7F9FA', background: groupLevel === 3 ? '#F5F5F5' : '#F7F9FA',
zIndex: columnIndex === 0 ? 6 : 5,
}} }}
> >
{columnIndex === 0 && {columnIndex === 0 && position !== 'right' && record.groupConfig[1] && (
position !== 'right' && <div className={s.groupContainer}>
record.groupConfig[1] && <Checkbox
`${record.groupConfig[1].colChsName}:${record.groupTextArr[1]}`} className={s.groupCheck}
checked={getGroupChecked(2)}
onClick={onToggleGroup.bind(null, 2)}
/>
<div className={s.groupExpand} onClick={onToggleGroupClose.bind(null, 2)}>
<IconFont type={getGroupExpanded(2)?"iconxiala1":"iconzirenwujinru"} />
</div>
<div className={s.groupContent}>
<span
className={s.groupText}
>{`${record.groupConfig[1].colChsName}:${record.groupTextArr[1]}`}</span>
<span className={s.groupCount}>{`共:${record.group2Children.length}条`}</span>
</div>
</div>
)}
</div> </div>
)} )}
{record.classList && record.classList[2] && ( {record.classList && record.classList[2] && (
...@@ -454,12 +549,27 @@ const Cell = (props: CellProps) => { ...@@ -454,12 +549,27 @@ const Cell = (props: CellProps) => {
top: groupLevel === 3 ? 80 : groupLevel === 2 ? 40 : 0, top: groupLevel === 3 ? 80 : groupLevel === 2 ? 40 : 0,
paddingLeft: '48px', paddingLeft: '48px',
background: '#F7F9FA', background: '#F7F9FA',
zIndex: columnIndex === 0 ? 6 : 5,
}} }}
> >
{columnIndex === 0 && {columnIndex === 0 && position !== 'right' && record.groupConfig[2] && (
position !== 'right' && <div className={s.groupContainer}>
record.groupConfig[2] && <Checkbox
`${record.groupConfig[2].colChsName}:${record.groupTextArr[2]}`} className={s.groupCheck}
checked={getGroupChecked(3)}
onClick={onToggleGroup.bind(null, 3)}
/>
<div className={s.groupExpand} onClick={onToggleGroupClose.bind(null, 3)}>
<IconFont type={getGroupExpanded(3)?"iconxiala1":"iconzirenwujinru"} />
</div>
<div className={s.groupContent}>
<span
className={s.groupText}
>{`${record.groupConfig[2].colChsName}:${record.groupTextArr[2]}`}</span>
<span className={s.groupCount}>{`共:${record.group3Children.length}条`}</span>
</div>
</div>
)}
</div> </div>
)} )}
{columnIndex === 0 && position !== 'right' && renderFirst()} {columnIndex === 0 && position !== 'right' && renderFirst()}
...@@ -470,7 +580,7 @@ const Cell = (props: CellProps) => { ...@@ -470,7 +580,7 @@ const Cell = (props: CellProps) => {
'cellUnit', 'cellUnit',
`table_${tableId}`, `table_${tableId}`,
`row_${rowIndex}`, `row_${rowIndex}`,
`col_${columnIndex}`, `col_${columnIndex}`
)} )}
data-selected-cell="0" data-selected-cell="0"
data-editing-cell="0" data-editing-cell="0"
......
...@@ -4,6 +4,7 @@ import { Checkbox, Tooltip } from 'antd'; ...@@ -4,6 +4,7 @@ import { Checkbox, Tooltip } from 'antd';
import _ from 'lodash'; import _ from 'lodash';
import s from './Column.less'; import s from './Column.less';
import { ColumnProps } from './interface'; import { ColumnProps } from './interface';
import { memoSelected } from './Cell';
export default class TableColumn extends PureComponent<ColumnProps> { export default class TableColumn extends PureComponent<ColumnProps> {
changeSort = (type: string) => { changeSort = (type: string) => {
...@@ -29,14 +30,11 @@ export default class TableColumn extends PureComponent<ColumnProps> { ...@@ -29,14 +30,11 @@ export default class TableColumn extends PureComponent<ColumnProps> {
getCheckbox = () => { getCheckbox = () => {
const { rowSelection, dataSource } = this.props; const { rowSelection, dataSource } = this.props;
const { selectedRows, onChange } = rowSelection; const { selectedRows, onChange } = rowSelection;
const selectIds = memoSelected(selectedRows);
let checked = false; let checked = false;
if (dataSource.length > 0 && selectedRows.length > 0) { if (dataSource.length > 0 && selectedRows.length > 0) {
for (let i = 0; i < dataSource.length; i++) { for (let i = 0; i < dataSource.length; i++) {
if ( if (!selectIds.includes(dataSource[i].id)) {
!selectedRows.some((item) => {
return item.id === dataSource[i].id;
})
) {
break; break;
} }
if (i === dataSource.length - 1) { if (i === dataSource.length - 1) {
...@@ -46,10 +44,10 @@ export default class TableColumn extends PureComponent<ColumnProps> { ...@@ -46,10 +44,10 @@ export default class TableColumn extends PureComponent<ColumnProps> {
} }
const onToggle = () => { const onToggle = () => {
if (typeof onChange === 'function') { if (typeof onChange === 'function') {
const data = _.cloneDeep(selectedRows); const data = _.cloneDeep(selectIds);
dataSource.map((item: any) => { dataSource.map((item: any) => {
const index = data.findIndex((temp: any) => { const index = data.findIndex((temp: any) => {
return temp.id === item.id; return temp === item.id;
}); });
if (checked) { if (checked) {
index > -1 && data.splice(index, 1); index > -1 && data.splice(index, 1);
......
...@@ -61,12 +61,13 @@ export default class AirTable extends Component<TableProps, TableState> { ...@@ -61,12 +61,13 @@ export default class AirTable extends Component<TableProps, TableState> {
memoizeTotalHeight: Function; memoizeTotalHeight: Function;
static getDerivedStateFromProps(nextProps: TableProps, prevState: TableState) { static getDerivedStateFromProps(nextProps: TableProps, prevState: TableState) {
const { columns, dataSource } = prevState; const { columns, prevPropsDataSource } = prevState;
const nextState: TableState = { const nextState: TableState = {
...prevState, ...prevState,
}; };
if (JSON.stringify(dataSource) !== JSON.stringify(nextProps.dataSource)) { if (JSON.stringify(prevPropsDataSource) !== JSON.stringify(nextProps.dataSource)) {
nextState.dataSource = nextProps.dataSource; nextState.dataSource = nextProps.dataSource;
nextState.prevPropsDataSource = nextProps.dataSource;
} }
if (JSON.stringify(columns) !== JSON.stringify(nextProps.columns)) { if (JSON.stringify(columns) !== JSON.stringify(nextProps.columns)) {
nextState.columns = nextProps.columns; nextState.columns = nextProps.columns;
...@@ -82,6 +83,7 @@ export default class AirTable extends Component<TableProps, TableState> { ...@@ -82,6 +83,7 @@ export default class AirTable extends Component<TableProps, TableState> {
dataSource, dataSource,
tableWidth: width || 0, tableWidth: width || 0,
tableHeight: height || 0, tableHeight: height || 0,
toggleGroup: 0,
}; };
this.config = getDefaultTableConfig(props); this.config = getDefaultTableConfig(props);
this.memoizeFormatColumns = memoizeOne(getFormatColumns); this.memoizeFormatColumns = memoizeOne(getFormatColumns);
...@@ -94,15 +96,36 @@ export default class AirTable extends Component<TableProps, TableState> { ...@@ -94,15 +96,36 @@ export default class AirTable extends Component<TableProps, TableState> {
this.memoizeData = memoizeOne(this.filterData); this.memoizeData = memoizeOne(this.filterData);
} }
componentDidUpdate(prevProps: Readonly<TableProps>): void { componentDidUpdate(prevProps: Readonly<TableProps>, prevState): void {
if ( if (
JSON.stringify(this.props.dataSource) !== JSON.stringify(prevProps.dataSource) JSON.stringify(this.props.dataSource) !== JSON.stringify(prevProps.dataSource)
|| JSON.stringify(this.props.groupConfig) !== JSON.stringify(prevProps.groupConfig) || JSON.stringify(this.props.groupConfig) !== JSON.stringify(prevProps.groupConfig)
|| prevState.toggleGroup !== this.state.toggleGroup
) { ) {
this.recomputeGridSize(); this.recomputeGridSize();
} }
} }
toggleGroup = (ids: number[], flag: boolean) => {
const { dataSource } = this.state;
const data: any[] = [];
dataSource.map((item) => {
const newItem = _.cloneDeep(item);
if (ids.includes(item.id)) {
data.push({
...newItem,
hidden: flag,
});
} else {
data.push(newItem);
}
});
this.setState({
dataSource: data,
toggleGroup: Math.random(),
});
};
// 获取表格显示数据 // 获取表格显示数据
filterData = (columns: ColumnProps[], dataSource: RowProps[]) => { filterData = (columns: ColumnProps[], dataSource: RowProps[]) => {
if (columns.length === 0 || dataSource.length === 0) { if (columns.length === 0 || dataSource.length === 0) {
...@@ -154,6 +177,7 @@ export default class AirTable extends Component<TableProps, TableState> { ...@@ -154,6 +177,7 @@ export default class AirTable extends Component<TableProps, TableState> {
this.grid6.recomputeGridSize(); this.grid6.recomputeGridSize();
} }
}; };
// 页面大小变化回调 // 页面大小变化回调
onResize = ({ width, height }: { width: number; height: number }) => { onResize = ({ width, height }: { width: number; height: number }) => {
this.setState( this.setState(
...@@ -183,6 +207,7 @@ export default class AirTable extends Component<TableProps, TableState> { ...@@ -183,6 +207,7 @@ export default class AirTable extends Component<TableProps, TableState> {
this.recomputeGridSize, this.recomputeGridSize,
); );
}; };
// 拖拽自定义固定列前置动作 // 拖拽自定义固定列前置动作
onResizeStartLeftDragFixed = () => { onResizeStartLeftDragFixed = () => {
// 拖动开始,将表格滚动回最左端 // 拖动开始,将表格滚动回最左端
...@@ -190,6 +215,7 @@ export default class AirTable extends Component<TableProps, TableState> { ...@@ -190,6 +215,7 @@ export default class AirTable extends Component<TableProps, TableState> {
this.grid4.scrollToPosition({ scrollLeft: 0 }); this.grid4.scrollToPosition({ scrollLeft: 0 });
} }
}; };
// 拖拽自定义固定列后置动作 // 拖拽自定义固定列后置动作
onResizeStopLeftDragFixed = (columns: ColumnProps[]) => { onResizeStopLeftDragFixed = (columns: ColumnProps[]) => {
this.setState( this.setState(
...@@ -199,6 +225,7 @@ export default class AirTable extends Component<TableProps, TableState> { ...@@ -199,6 +225,7 @@ export default class AirTable extends Component<TableProps, TableState> {
this.recomputeGridSize, this.recomputeGridSize,
); );
}; };
// 拖拽自定义固定列前置动作 // 拖拽自定义固定列前置动作
onResizeStartRightDragFixed = () => { onResizeStartRightDragFixed = () => {
// 拖动开始,将表格滚动回最右端 // 拖动开始,将表格滚动回最右端
...@@ -208,6 +235,7 @@ export default class AirTable extends Component<TableProps, TableState> { ...@@ -208,6 +235,7 @@ export default class AirTable extends Component<TableProps, TableState> {
this.grid4.scrollToCell({ columnIndex: showColumns.length - 1 }); this.grid4.scrollToCell({ columnIndex: showColumns.length - 1 });
} }
}; };
// 拖拽自定义固定列后置动作 // 拖拽自定义固定列后置动作
onResizeStopRightDragFixed = (columns: ColumnProps[]) => { onResizeStopRightDragFixed = (columns: ColumnProps[]) => {
this.setState( this.setState(
...@@ -217,6 +245,7 @@ export default class AirTable extends Component<TableProps, TableState> { ...@@ -217,6 +245,7 @@ export default class AirTable extends Component<TableProps, TableState> {
this.recomputeGridSize, this.recomputeGridSize,
); );
}; };
// 拖拽滚动表格 // 拖拽滚动表格
onDragSortedMove = (direction: string, step: number) => { onDragSortedMove = (direction: string, step: number) => {
// 拖动超过视图范围,将表格左右滚动 // 拖动超过视图范围,将表格左右滚动
...@@ -234,6 +263,7 @@ export default class AirTable extends Component<TableProps, TableState> { ...@@ -234,6 +263,7 @@ export default class AirTable extends Component<TableProps, TableState> {
} }
} }
}; };
// 拖拽排序回调 // 拖拽排序回调
onDragSortedCb = (columns: ColumnProps[]) => { onDragSortedCb = (columns: ColumnProps[]) => {
this.setState( this.setState(
...@@ -243,6 +273,7 @@ export default class AirTable extends Component<TableProps, TableState> { ...@@ -243,6 +273,7 @@ export default class AirTable extends Component<TableProps, TableState> {
this.recomputeGridSize, this.recomputeGridSize,
); );
}; };
// 渲染表头 // 渲染表头
renderHeaderCell = ( renderHeaderCell = (
{ showColumns, position }: { showColumns: ColumnProps[]; position?: string }, { showColumns, position }: { showColumns: ColumnProps[]; position?: string },
...@@ -425,13 +456,17 @@ export default class AirTable extends Component<TableProps, TableState> { ...@@ -425,13 +456,17 @@ export default class AirTable extends Component<TableProps, TableState> {
tableId={tableId} tableId={tableId}
maxPopHeight={maxPopHeight} maxPopHeight={maxPopHeight}
renderFirstLeft={renderFirstLeft} renderFirstLeft={renderFirstLeft}
toggleGroup={this.toggleGroup}
dataSource={dataSource}
/> />
); );
}; };
render() { render() {
const { loading, noDataPlaceholder, loadComp, canFixed, tableId, cachedFeAttr, onDragFixed } = this.props; const {
const { columns, dataSource, tableWidth = 0, tableHeight = 0 } = this.state; loading, noDataPlaceholder, loadComp, canFixed, tableId, cachedFeAttr, onDragFixed,
} = this.props;
const { columns, dataSource, tableWidth = 0, tableHeight = 0, toggleGroup } = this.state;
const { overscanColumnCount, overscanRowCount, rowHeight, headerHeight, columnWidth } = this.config; const { overscanColumnCount, overscanRowCount, rowHeight, headerHeight, columnWidth } = this.config;
const scrollbarWidth = scrollbarSize() || 0; const scrollbarWidth = scrollbarSize() || 0;
const formatColumns = this.memoizeFormatColumns(columns, cachedFeAttr, tableId); const formatColumns = this.memoizeFormatColumns(columns, cachedFeAttr, tableId);
...@@ -439,9 +474,9 @@ export default class AirTable extends Component<TableProps, TableState> { ...@@ -439,9 +474,9 @@ export default class AirTable extends Component<TableProps, TableState> {
const leftColumns = this.memoizeLeftColumns(showColumns); const leftColumns = this.memoizeLeftColumns(showColumns);
const rightColumns = this.memoizeRightColumns(showColumns); const rightColumns = this.memoizeRightColumns(showColumns);
// 有隐藏列时,修正数据与列头不匹配问题 // 有隐藏列时,修正数据与列头不匹配问题
const showData = this.memoizeData(showColumns, dataSource); const showData = this.memoizeData(showColumns, dataSource, toggleGroup);
const leftData = this.memoizeData(leftColumns, dataSource); const leftData = this.memoizeData(leftColumns, dataSource, toggleGroup);
const rightData = this.memoizeData(rightColumns, dataSource); const rightData = this.memoizeData(rightColumns, dataSource, toggleGroup);
// 左侧固定列数量 // 左侧固定列数量
const leftCount = leftColumns.length; const leftCount = leftColumns.length;
const rightCount = rightColumns.length; const rightCount = rightColumns.length;
...@@ -451,7 +486,7 @@ export default class AirTable extends Component<TableProps, TableState> { ...@@ -451,7 +486,7 @@ export default class AirTable extends Component<TableProps, TableState> {
const rightWidth = this.memoizeLeftWidth(rightColumns, showColumns, columnWidth, tableWidth); const rightWidth = this.memoizeLeftWidth(rightColumns, showColumns, columnWidth, tableWidth);
const tableBodyHeight: number = tableHeight - headerHeight; const tableBodyHeight: number = tableHeight - headerHeight;
const { totalWidth } = this.memoizeTotalWidth(showColumns, columnWidth); const { totalWidth } = this.memoizeTotalWidth(showColumns, columnWidth);
const totalHeight = this.memoizeTotalHeight(dataSource, rowHeight); const totalHeight = this.memoizeTotalHeight(dataSource, rowHeight, toggleGroup);
let realWidth = tableWidth; let realWidth = tableWidth;
let paddingRight = 0; let paddingRight = 0;
if (rowCount > 0 && totalHeight > tableBodyHeight) { if (rowCount > 0 && totalHeight > tableBodyHeight) {
...@@ -460,316 +495,318 @@ export default class AirTable extends Component<TableProps, TableState> { ...@@ -460,316 +495,318 @@ export default class AirTable extends Component<TableProps, TableState> {
} }
return ( return (
<Consumer> <Consumer>
{({ locale }) => ( {({ locale }) => {
<ScrollSync> return (
{({ onScroll, scrollLeft, scrollTop }: any) => { <ScrollSync>
return ( {({ onScroll, scrollLeft, scrollTop }: any) => {
<div return (
className={styles.tableContainer} <div
style={{ className={styles.tableContainer}
paddingRight, style={{
}} paddingRight,
id={`apolloTable_${tableId}`} }}
> id={`apolloTable_${tableId}`}
{totalWidth > tableWidth && leftCount > 0 && ( >
<div {totalWidth > tableWidth && leftCount > 0 && (
className={styles.leftSideContainer} <div
style={{ className={styles.leftSideContainer}
width: `${leftWidth}px`, style={{
height: `${tableBodyHeight - scrollbarWidth + headerHeight}px`, width: `${leftWidth}px`,
}} height: `${tableBodyHeight - scrollbarWidth + headerHeight}px`,
> }}
{ >
{
// 左侧表头 // 左侧表头
<div <div
className={styles.leftSideHeaderContainer} className={styles.leftSideHeaderContainer}
style={{ style={{
left: 0, left: 0,
}}
>
<Grid
ref={(dom: any) => {
this.grid1 = dom;
}} }}
className={styles.headerGrid} >
columnWidth={this.getColumnWidth.bind(this, { <Grid
columns: showColumns, ref={(dom: any) => {
showColumns: leftColumns, this.grid1 = dom;
})} }}
columnCount={leftCount} className={styles.headerGrid}
width={leftWidth} columnWidth={this.getColumnWidth.bind(this, {
rowHeight={headerHeight} columns: showColumns,
rowCount={1} showColumns: leftColumns,
height={headerHeight} })}
cellRenderer={this.renderHeaderCell.bind(this, { columnCount={leftCount}
showColumns: leftColumns, width={leftWidth}
position: 'left', rowHeight={headerHeight}
})} rowCount={1}
/> height={headerHeight}
</div> cellRenderer={this.renderHeaderCell.bind(this, {
} showColumns: leftColumns,
{ position: 'left',
})}
/>
</div>
}
{
// 左侧固定列 // 左侧固定列
<div <div
className={styles.leftSideGridContainer} className={styles.leftSideGridContainer}
style={{ style={{
left: 0, left: 0,
top: headerHeight, top: headerHeight,
}}
>
<Grid
ref={(dom: any) => {
this.grid2 = dom;
}} }}
className={styles.sideGrid} >
overscanRowCount={overscanRowCount} <Grid
cellRenderer={this.renderBodyCell.bind(this, { ref={(dom: any) => {
showColumns: leftColumns, this.grid2 = dom;
showData: leftData, }}
position: 'left', className={styles.sideGrid}
})} overscanRowCount={overscanRowCount}
columnWidth={this.getColumnWidth.bind(this, { cellRenderer={this.renderBodyCell.bind(this, {
columns: showColumns, showColumns: leftColumns,
showColumns: leftColumns, showData: leftData,
})} position: 'left',
onScroll={(...arg: Array<Object>) => { })}
onScroll({ scrollTop: arg[0].scrollTop }); columnWidth={this.getColumnWidth.bind(this, {
this.onScroll(arg[0]); columns: showColumns,
}} showColumns: leftColumns,
columnCount={leftCount} })}
width={leftWidth + scrollbarWidth} onScroll={(...arg: Array<Object>) => {
rowHeight={getRowHeight.bind(this, { onScroll({ scrollTop: arg[0].scrollTop });
dataSource, this.onScroll(arg[0]);
rowHeight, }}
})} columnCount={leftCount}
rowCount={rowCount} width={leftWidth + scrollbarWidth}
height={tableBodyHeight - scrollbarWidth} rowHeight={getRowHeight.bind(this, {
scrollTop={scrollTop} dataSource,
/> rowHeight,
</div> })}
} rowCount={rowCount}
</div> height={tableBodyHeight - scrollbarWidth}
)} scrollTop={scrollTop}
{canFixed && ( />
<LeftDragFixed </div>
tableId={tableId} }
initLeft={leftWidth} </div>
initTop={headerHeight} )}
tableWidth={tableWidth} {canFixed && (
showColumns={showColumns} <LeftDragFixed
columnWidth={columnWidth} tableId={tableId}
columns={formatColumns} initLeft={leftWidth}
onResizeStart={this.onResizeStartLeftDragFixed} initTop={headerHeight}
onResizeStop={this.onResizeStopLeftDragFixed} tableWidth={tableWidth}
onDragFixed={onDragFixed} showColumns={showColumns}
cachedFeAttr={cachedFeAttr} columnWidth={columnWidth}
/> columns={formatColumns}
)} onResizeStart={this.onResizeStartLeftDragFixed}
<div className={styles.centerContainer}> onResizeStop={this.onResizeStopLeftDragFixed}
<AutoSizer onResize={this.onResize}> onDragFixed={onDragFixed}
{({ width, height }: any) => { cachedFeAttr={cachedFeAttr}
return ( />
<div> )}
{ <div className={styles.centerContainer}>
<AutoSizer onResize={this.onResize}>
{({ width, height }: any) => {
return (
<div>
{
// 中部表头 // 中部表头
<div <div
style={{ style={{
backgroundColor: 'rgba(246, 246, 246, 1)', backgroundColor: 'rgba(246, 246, 246, 1)',
height: headerHeight, height: headerHeight,
width, width,
}}
>
<Grid
ref={(dom: any) => {
this.grid3 = dom;
}} }}
className={styles.headerGrid} >
overscanColumnCount={overscanColumnCount}
columnWidth={this.getColumnWidth.bind(this, {
columns: showColumns,
showColumns,
})}
columnCount={columnCount}
width={width}
rowHeight={headerHeight}
rowCount={1}
height={headerHeight}
scrollLeft={scrollLeft}
cellRenderer={this.renderHeaderCell.bind(this, {
showColumns,
position: 'center',
})}
/>
</div>
}
{
// 中部内容
<div
style={{
height: tableBodyHeight,
width: tableWidth,
}}
>
{rowCount > 0 ? (
<Grid <Grid
ref={(dom: any) => { ref={(dom: any) => {
this.grid4 = dom; this.grid3 = dom;
}} }}
className={styles.centerGrid} className={styles.headerGrid}
overscanColumnCount={overscanColumnCount} overscanColumnCount={overscanColumnCount}
overscanRowCount={overscanRowCount}
columnWidth={this.getColumnWidth.bind(this, { columnWidth={this.getColumnWidth.bind(this, {
columns: showColumns, columns: showColumns,
showColumns, showColumns,
})} })}
columnCount={columnCount} columnCount={columnCount}
width={realWidth} width={width}
rowHeight={getRowHeight.bind(this, { rowHeight={headerHeight}
dataSource, rowCount={1}
rowHeight, height={headerHeight}
})} scrollLeft={scrollLeft}
rowCount={rowCount} cellRenderer={this.renderHeaderCell.bind(this, {
onScroll={(...arg: Array<Object>) => {
onScroll(...arg);
this.onScroll(arg[0]);
}}
scrollTop={scrollTop}
height={tableBodyHeight}
cellRenderer={this.renderBodyCell.bind(this, {
showColumns, showColumns,
showData,
position: 'center', position: 'center',
})} })}
/> />
) : ( </div>
columnCount > 0 && }
!loading && ( {
<Empty // 中部内容
className={styles.defaultEmpty} <div
description={ style={{
noDataPlaceholder || locale.empty height: tableBodyHeight,
} width: tableWidth,
}}
>
{rowCount > 0 ? (
<Grid
ref={(dom: any) => {
this.grid4 = dom;
}}
className={styles.centerGrid}
overscanColumnCount={overscanColumnCount}
overscanRowCount={overscanRowCount}
columnWidth={this.getColumnWidth.bind(this, {
columns: showColumns,
showColumns,
})}
columnCount={columnCount}
width={realWidth}
rowHeight={getRowHeight.bind(this, {
dataSource,
rowHeight,
})}
rowCount={rowCount}
onScroll={(...arg: Array<Object>) => {
onScroll(...arg);
this.onScroll(arg[0]);
}}
scrollTop={scrollTop}
height={tableBodyHeight}
cellRenderer={this.renderBodyCell.bind(this, {
showColumns,
showData,
position: 'center',
})}
/> />
) ) : (
)} columnCount > 0
</div> && !loading && (
} <Empty
</div> className={styles.defaultEmpty}
); description={
}} noDataPlaceholder || locale.empty
</AutoSizer> }
</div> />
{false && ( )
<RightDragFixed )}
tableId={tableId} </div>
initLeft={tableWidth - rightWidth} }
initTop={headerHeight} </div>
tableWidth={tableWidth} );
showColumns={showColumns} }}
columnWidth={columnWidth} </AutoSizer>
columns={formatColumns} </div>
paddingRight={paddingRight} {false && (
onResizeStart={this.onResizeStartRightDragFixed} <RightDragFixed
onResizeStop={this.onResizeStopRightDragFixed} tableId={tableId}
onDragFixed={onDragFixed} initLeft={tableWidth - rightWidth}
cachedFeAttr={cachedFeAttr} initTop={headerHeight}
/> tableWidth={tableWidth}
)} showColumns={showColumns}
{totalWidth > tableWidth && rightCount > 0 && ( columnWidth={columnWidth}
<div columns={formatColumns}
className={styles.rightSideContainer} paddingRight={paddingRight}
style={{ onResizeStart={this.onResizeStartRightDragFixed}
width: `${rightWidth}px`, onResizeStop={this.onResizeStopRightDragFixed}
height: `${tableBodyHeight - scrollbarWidth + headerHeight}px`, onDragFixed={onDragFixed}
right: paddingRight, cachedFeAttr={cachedFeAttr}
}} />
> )}
{ {totalWidth > tableWidth && rightCount > 0 && (
<div
className={styles.rightSideContainer}
style={{
width: `${rightWidth}px`,
height: `${tableBodyHeight - scrollbarWidth + headerHeight}px`,
right: paddingRight,
}}
>
{
// 右侧表头 // 右侧表头
<div <div
className={styles.rightSideHeaderContainer} className={styles.rightSideHeaderContainer}
style={{ style={{
right: 0, right: 0,
}}
>
<Grid
ref={(dom: any) => {
this.grid5 = dom;
}} }}
className={styles.headerGrid} >
columnWidth={this.getColumnWidth.bind(this, { <Grid
columns: showColumns, ref={(dom: any) => {
showColumns: rightColumns, this.grid5 = dom;
})} }}
columnCount={rightCount} className={styles.headerGrid}
width={rightWidth} columnWidth={this.getColumnWidth.bind(this, {
rowHeight={headerHeight} columns: showColumns,
rowCount={1} showColumns: rightColumns,
height={headerHeight} })}
cellRenderer={this.renderHeaderCell.bind(this, { columnCount={rightCount}
showColumns: rightColumns, width={rightWidth}
position: 'right', rowHeight={headerHeight}
})} rowCount={1}
/> height={headerHeight}
</div> cellRenderer={this.renderHeaderCell.bind(this, {
} showColumns: rightColumns,
{ position: 'right',
})}
/>
</div>
}
{
// 右侧固定列 // 右侧固定列
<div <div
className={styles.rightSideGridContainer} className={styles.rightSideGridContainer}
style={{ style={{
position: 'absolute', position: 'absolute',
right: 0, right: 0,
top: headerHeight, top: headerHeight,
marginRight: -scrollbarWidth, marginRight: -scrollbarWidth,
}}
>
<Grid
ref={(dom: any) => {
this.grid6 = dom;
}} }}
className={styles.sideGrid} >
overscanRowCount={overscanRowCount} <Grid
cellRenderer={this.renderBodyCell.bind(this, { ref={(dom: any) => {
showColumns: rightColumns, this.grid6 = dom;
showData: rightData, }}
position: 'right', className={styles.sideGrid}
})} overscanRowCount={overscanRowCount}
columnWidth={this.getColumnWidth.bind(this, { cellRenderer={this.renderBodyCell.bind(this, {
columns: showColumns, showColumns: rightColumns,
showColumns: rightColumns, showData: rightData,
})} position: 'right',
onScroll={(...arg: Array<Object>) => { })}
onScroll({ scrollTop: arg[0].scrollTop }); columnWidth={this.getColumnWidth.bind(this, {
this.onScroll(arg[0]); columns: showColumns,
}} showColumns: rightColumns,
columnCount={rightCount} })}
width={rightWidth + scrollbarWidth} onScroll={(...arg: Array<Object>) => {
rowHeight={getRowHeight.bind(this, { onScroll({ scrollTop: arg[0].scrollTop });
dataSource, this.onScroll(arg[0]);
rowHeight, }}
})} columnCount={rightCount}
rowCount={rowCount} width={rightWidth + scrollbarWidth}
height={tableBodyHeight - scrollbarWidth} rowHeight={getRowHeight.bind(this, {
scrollTop={scrollTop} dataSource,
/> rowHeight,
</div> })}
} rowCount={rowCount}
height={tableBodyHeight - scrollbarWidth}
scrollTop={scrollTop}
/>
</div>
}
</div>
)}
<div className={styles.fillHandleWrapper} />
<div className={styles.loading} style={{ top: `${tableBodyHeight / 2}px` }}>
{loading && (loadComp || <Spin />)}
</div> </div>
)} <div className={styles.widthHandleWrapper} id={`dividerWrap_${tableId}`}>
<div className={styles.fillHandleWrapper} /> <div className={styles.widthHandle} id={`divider_${tableId}`} />
<div className={styles.loading} style={{ top: `${tableBodyHeight / 2}px` }}> </div>
{loading && (loadComp ? loadComp : <Spin />)} <div id="columnCopyDiv" className={styles.columnCopyDiv} />
</div>
<div className={styles.widthHandleWrapper} id={`dividerWrap_${tableId}`}>
<div className={styles.widthHandle} id={`divider_${tableId}`} />
</div> </div>
<div id="columnCopyDiv" className={styles.columnCopyDiv} /> );
</div> }}
); </ScrollSync>
}} );
</ScrollSync> }}
)}
</Consumer> </Consumer>
); );
} }
......
...@@ -47,11 +47,11 @@ const formatData = (config: string[], dataSource: any[]) => { ...@@ -47,11 +47,11 @@ const formatData = (config: string[], dataSource: any[]) => {
} }
const map: any = {}; const map: any = {};
// 一级分组条件 // 一级分组条件
const group1 = config[0]; const group1:any = config[0];
// 二级分组条件 // 二级分组条件
const group2 = config[1]; const group2:any = config[1];
// 三级分组条件 // 三级分组条件
const group3 = config[2]; const group3:any = config[2];
// 遍历数据默认已排序,根据分组级别给每行添加分组class // 遍历数据默认已排序,根据分组级别给每行添加分组class
return dataSource.map((row: any) => { return dataSource.map((row: any) => {
const groupKeyArr: string[] = []; const groupKeyArr: string[] = [];
...@@ -79,37 +79,52 @@ const formatData = (config: string[], dataSource: any[]) => { ...@@ -79,37 +79,52 @@ const formatData = (config: string[], dataSource: any[]) => {
const group1Key = groupKeyArr[0]; const group1Key = groupKeyArr[0];
const group1Text = groupTextArr[0]; const group1Text = groupTextArr[0];
if (!map[group1Key]) { if (!map[group1Key]) {
map[group1Key] = group1Text; map[group1Key] = {
text: group1Text,
children: [],
};
if (row.classList) { if (row.classList) {
row.classList[0] = 'groupLevel1'; row.classList[0] = 'groupLevel1';
} else { } else {
row.classList = ['groupLevel1']; row.classList = ['groupLevel1'];
} }
row.group1Children = map[group1Key].children;
} }
map[group1Key].children.push(row.id);
} }
if (groupKeyArr[1]) { if (groupKeyArr[1]) {
const group2Key = `${groupKeyArr[0]}-${groupKeyArr[1]}`; const group2Key = `${groupKeyArr[0]}-${groupKeyArr[1]}`;
const group2Text = `${groupTextArr[0]}-${groupTextArr[1]}`; const group2Text = `${groupTextArr[0]}-${groupTextArr[1]}`;
if (!map[group2Key]) { if (!map[group2Key]) {
map[group2Key] = group2Text; map[group2Key] = {
text: group2Text,
children: [],
};
if (row.classList) { if (row.classList) {
row.classList[1] = 'groupLevel2'; row.classList[1] = 'groupLevel2';
} else { } else {
row.classList = ['', 'groupLevel2', '']; row.classList = ['', 'groupLevel2', ''];
} }
row.group2Children = map[group2Key].children;
} }
map[group2Key].children.push(row.id);
} }
if (groupKeyArr[2]) { if (groupKeyArr[2]) {
const group3Key = groupKeyArr.join('-'); const group3Key = groupKeyArr.join('-');
const group3Text = groupTextArr.join('-'); const group3Text = groupTextArr.join('-');
if (!map[group3Key]) { if (!map[group3Key]) {
map[group3Key] = group3Text; map[group3Key] = {
text: group3Text,
children: [],
};
if (row.classList) { if (row.classList) {
row.classList[2] = 'groupLevel3'; row.classList[2] = 'groupLevel3';
} else { } else {
row.classList = ['', '', 'groupLevel3']; row.classList = ['', '', 'groupLevel3'];
} }
row.group3Children = map[group3Key].children;
} }
map[group3Key].children.push(row.id);
} }
row.groupLevel = groupKeyArr.length; row.groupLevel = groupKeyArr.length;
row.groupKeyArr = groupKeyArr; row.groupKeyArr = groupKeyArr;
...@@ -224,7 +239,9 @@ class AirTable extends React.Component<CommonProps, CommonState> { ...@@ -224,7 +239,9 @@ class AirTable extends React.Component<CommonProps, CommonState> {
return ( return (
<Provider value={{ locale: this.getContext() }}> <Provider value={{ locale: this.getContext() }}>
<div className={classNames(styles.container, className)}> <div className={classNames(styles.container, className)}>
{operateConfig && <OperateConfig selfClass={selfClass} columns={columns} operateConfig={operateConfig} />} {operateConfig && (
<OperateConfig selfClass={selfClass} columns={columns} operateConfig={operateConfig} />
)}
<div className={classNames(styles.tableContainer, tableClassName)}> <div className={classNames(styles.tableContainer, tableClassName)}>
{tableOperateConfig && ( {tableOperateConfig && (
<div className={styles.tableOperateContainer}> <div className={styles.tableOperateContainer}>
......
...@@ -94,6 +94,8 @@ export interface TableState { ...@@ -94,6 +94,8 @@ export interface TableState {
groupConfig?: any[]; groupConfig?: any[];
tableHeight?: number; tableHeight?: number;
tableWidth?: number; tableWidth?: number;
toggleGroup?: number;
prevPropsDataSource?: RowProps[];
} }
export interface CommonProps extends TableProps { export interface CommonProps extends TableProps {
operateConfig?: OperateConfigProps; // 操作栏 operateConfig?: OperateConfigProps; // 操作栏
...@@ -142,6 +144,8 @@ export interface CellProps { ...@@ -142,6 +144,8 @@ export interface CellProps {
tableId?: string | number; tableId?: string | number;
maxPopHeight?: string | number; maxPopHeight?: string | number;
renderFirstLeft?: Function; renderFirstLeft?: Function;
toggleGroup: Function;
dataSource: RowProps[];
} }
export interface EditCellProps { export interface EditCellProps {
......
import memoizeOne from 'memoize-one'; import memoizeOne from 'memoize-one';
import { ColumnProps, RowProps } from '../component/interface';
import { getCache, saveCache } from '@/submodule/components/apolloTable/utils/cache'; import { getCache, saveCache } from '@/submodule/components/apolloTable/utils/cache';
import { ColumnProps, RowProps } from '../component/interface';
// 获取左侧固定列数量 // 获取左侧固定列数量
export const getLeftColumns = (columns: ColumnProps[]) => { export const getLeftColumns = (columns: ColumnProps[]) => {
...@@ -64,8 +64,8 @@ export const getRowHeight = ( ...@@ -64,8 +64,8 @@ export const getRowHeight = (
{ dataSource, rowHeight }: { dataSource: RowProps[]; rowHeight: number }, { dataSource, rowHeight }: { dataSource: RowProps[]; rowHeight: number },
{ index }: { index: number }, { index }: { index: number },
) => { ) => {
const { classList } = dataSource[index]; const { classList, hidden } = dataSource[index];
let len = 1; let len = 0;
if (classList) { if (classList) {
classList.map((item) => { classList.map((item) => {
if (item) { if (item) {
...@@ -73,11 +73,12 @@ export const getRowHeight = ( ...@@ -73,11 +73,12 @@ export const getRowHeight = (
} }
}); });
} }
return rowHeight * len; const basic = hidden ? 0 : rowHeight;
return 40 * len + basic;
}; };
// 获取数据总高度 // 获取数据总高度
export const getTotalHeight = (dataSource: RowProps[], rowHeight: number) => { export const getTotalHeight = (dataSource: RowProps[], rowHeight: number, toggleGroup:boolean) => {
let height = 0; let height = 0;
dataSource.map((item: any, index: number) => { dataSource.map((item: any, index: number) => {
height += getRowHeight({ dataSource, rowHeight }, { index }); height += getRowHeight({ dataSource, rowHeight }, { index });
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment