Merge pull request #5141 from wanglinfang2014/feat-table

fix: crud2 columns更新问题修复;table-v2调整为table2;table2的key调整为name
This commit is contained in:
yangwei9012 2022-08-23 15:26:19 +08:00 committed by GitHub
commit 9980bcb243
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 670 additions and 538 deletions

View File

@ -791,10 +791,10 @@ export const components = [
)
},
// {
// label: 'Table v2 表格',
// path: '/zh-CN/components/table-v2',
// label: 'Table2 表格',
// path: '/zh-CN/components/table2',
// component: React.lazy(() =>
// import('../../docs/zh-CN/components/table-v2.md').then(wrapDoc)
// import('../../docs/zh-CN/components/table2.md').then(wrapDoc)
// )
// },
{

View File

@ -134,7 +134,7 @@ export const CRUDStore = ServiceStore.named('CRUDStore')
loadDataMode?: boolean;
syncResponse2Query?: boolean;
columns?: Array<any>;
isTableV2?: Boolean; // 是否是 CRUD2
isTable2?: Boolean; // 是否是 CRUD2
}
) => Promise<any> = flow(function* getInitData(
api: Api,
@ -165,8 +165,7 @@ export const CRUDStore = ServiceStore.named('CRUDStore')
if (Array.isArray(options.columns)) {
options.columns.forEach((column: any) => {
let value: any;
// 兼容新老版本的name和key
const key = column.name || column.key;
const key = column.name;
if (
column.searchable &&
key &&
@ -311,7 +310,7 @@ export const CRUDStore = ServiceStore.named('CRUDStore')
if (Array.isArray(options.columns)) {
options.columns.forEach((column: any) => {
let value: any;
const key = column.name || column.key;
const key = column.name;
if (
column.searchable &&
key &&
@ -337,7 +336,7 @@ export const CRUDStore = ServiceStore.named('CRUDStore')
if (Array.isArray(columns)) {
self.columns = columns.concat();
} else if (rest.isTableV2) {
} else if (rest.isTable2) {
self.columns = options.columns;
}

View File

@ -12,7 +12,7 @@ import {ComboStore, IComboStore} from './combo';
import {FormStore, IFormStore} from './form';
import {CRUDStore, ICRUDStore} from './crud';
import {IColumn, IRow, ITableStore, TableStore} from './table';
import {IColumnV2, IRowV2, ITableStoreV2, TableStoreV2} from './table-v2';
import {IColumn2, IRow2, ITableStore2, TableStore2} from './table2';
import {IListStore, ListStore} from './list';
import {IModalStore, ModalStore} from './modal';
import {TranslateFn} from '../locale';
@ -34,7 +34,7 @@ const allowedStoreList = [
ComboStore,
CRUDStore,
TableStore,
TableStoreV2,
TableStore2,
ListStore,
ModalStore,
FormItemStore,
@ -115,10 +115,10 @@ export {
IColumn,
IRow,
ITableStore,
TableStoreV2,
ITableStoreV2,
IColumnV2,
IRowV2,
TableStore2,
ITableStore2,
IColumn2,
IRow2,
ListStore,
IListStore,
ModalStore,

View File

@ -37,7 +37,7 @@ class ServerError extends Error {
export const Column = types
.model('Column', {
title: types.optional(types.frozen(), undefined),
key: '',
name: '',
toggled: false,
breakpoint: types.optional(types.frozen(), undefined),
pristine: types.optional(types.frozen(), undefined),
@ -52,7 +52,7 @@ export const Column = types
.actions(self => ({
toggleToggle() {
self.toggled = !self.toggled;
const table = getParent(self, 2) as ITableStoreV2;
const table = getParent(self, 2) as ITableStore2;
if (!table.activeToggaleColumns.length) {
self.toggled = true;
@ -65,15 +65,15 @@ export const Column = types
}
}));
export type IColumnV2 = Instance<typeof Column>;
export type SColumnV2 = SnapshotIn<typeof Column>;
export type IColumn2 = Instance<typeof Column>;
export type SColumn2 = SnapshotIn<typeof Column>;
export const Row = types
.model('Row', {
storeType: 'Row',
id: types.identifier,
parentId: '',
key: types.string,
name: types.string,
pristine: types.frozen({} as any), // 原始数据
data: types.frozen({} as any),
index: types.number,
@ -87,8 +87,8 @@ export const Row = types
})
.views(self => ({
get checked(): boolean {
return (getParent(self, self.depth * 2) as ITableStoreV2).isSelected(
self as IRowV2
return (getParent(self, self.depth * 2) as ITableStore2).isSelected(
self as IRow2
);
},
@ -112,9 +112,9 @@ export const Row = types
children = self.children.map(item => item.locals);
}
const parent = getParent(self, 2) as ITableStoreV2;
const parent = getParent(self, 2) as ITableStore2;
return createObject(
extendObject((getParent(self, self.depth * 2) as ITableStoreV2).data, {
extendObject((getParent(self, self.depth * 2) as ITableStore2).data, {
index: self.index,
// todo 以后再支持多层,目前先一层
parent: parent.storeType === Row.name ? parent.data : undefined
@ -188,10 +188,10 @@ export const Row = types
}
}));
export type IRowV2 = Instance<typeof Row>;
export type SRowV2 = SnapshotIn<typeof Row>;
export type IRow2 = Instance<typeof Row>;
export type SRow2 = SnapshotIn<typeof Row>;
export const TableStoreV2 = ServiceStore.named('TableStoreV2')
export const TableStore2 = ServiceStore.named('TableStore2')
.props({
columns: types.array(Column),
rows: types.array(Row),
@ -235,7 +235,7 @@ export const TableStoreV2 = ServiceStore.named('TableStoreV2')
return getToggableColumns().filter(item => item.toggled);
}
function getAllFilteredColumns(columns?: Array<SColumnV2>): Array<any> {
function getAllFilteredColumns(columns?: Array<SColumn2>): Array<any> {
if (columns) {
return columns
.filter(
@ -263,8 +263,8 @@ export const TableStoreV2 = ServiceStore.named('TableStoreV2')
}
function getUnSelectedRows() {
return flattenTree<IRowV2>(self.rows).filter(
(item: IRowV2) => !item.checked
return flattenTree<IRow2>(self.rows).filter(
(item: IRow2) => !item.checked
);
}
@ -276,7 +276,7 @@ export const TableStoreV2 = ServiceStore.named('TableStoreV2')
});
}
function getRowByIndex(rowIndex: number, levels?: Array<string>): IRowV2 {
function getRowByIndex(rowIndex: number, levels?: Array<string>): IRow2 {
if (levels && levels.length > 0) {
const index = +(levels.shift() || 0);
return getRowByIndex(index, levels);
@ -284,12 +284,12 @@ export const TableStoreV2 = ServiceStore.named('TableStoreV2')
return self.rows[rowIndex];
}
function isSelected(row: IRowV2): boolean {
function isSelected(row: IRow2): boolean {
return !!~self.selectedRows.indexOf(row);
}
function getMovedRows() {
return flattenTree(self.rows).filter((item: IRowV2) => item.moved);
return flattenTree(self.rows).filter((item: IRow2) => item.moved);
}
function getMoved() {
@ -358,9 +358,9 @@ export const TableStoreV2 = ServiceStore.named('TableStoreV2')
};
})
.actions(self => {
function updateColumns(columns: Array<SColumnV2>) {
function updateColumns(columns: Array<SColumn2>) {
if (columns && Array.isArray(columns)) {
let cols: Array<SColumnV2> = columns.filter(column => column).concat();
let cols: Array<SColumn2> = columns.filter(column => column).concat();
cols = cols.map((item, index) => ({
...item,
@ -377,7 +377,7 @@ export const TableStoreV2 = ServiceStore.named('TableStoreV2')
return;
}
function update(config: Partial<STableStoreV2>) {
function update(config: Partial<STableStore2>) {
config.columnsTogglable !== void 0 &&
(self.columnsTogglable = config.columnsTogglable);
@ -393,11 +393,11 @@ export const TableStoreV2 = ServiceStore.named('TableStoreV2')
}
}
function exchange(fromIndex: number, toIndex: number, item?: IRowV2) {
function exchange(fromIndex: number, toIndex: number, item?: IRow2) {
item = item || self.rows[fromIndex];
if (item.parentId) {
const parent: IRowV2 = self.getRowById(item.parentId) as any;
const parent: IRow2 = self.getRowById(item.parentId) as any;
const offset = parent.children.indexOf(item) - fromIndex;
toIndex += offset;
fromIndex += offset;
@ -436,7 +436,7 @@ export const TableStoreV2 = ServiceStore.named('TableStoreV2')
const key =
location.pathname +
self.path +
self.toggableColumns.map(item => item.key || item.index).join('-');
self.toggableColumns.map(item => item.name || item.index).join('-');
localStorage.setItem(
key,
JSON.stringify(self.activeToggaleColumns.map(item => item.index))
@ -528,7 +528,7 @@ export const TableStoreV2 = ServiceStore.named('TableStoreV2')
}
// 尽可能的复用 row
function replaceRow(arr: Array<SRowV2>, reUseRow?: boolean) {
function replaceRow(arr: Array<SRow2>, reUseRow?: boolean) {
if (reUseRow === false) {
self.rows.replace(arr.map(item => Row.create(item)));
return;
@ -578,7 +578,7 @@ export const TableStoreV2 = ServiceStore.named('TableStoreV2')
return {
id: id,
parentId,
key: String(`${pindex}-${depth}-${index}`),
name: String(`${pindex}-${depth}-${index}`),
path: `${path}${index}`,
depth: depth,
index: index,
@ -604,12 +604,12 @@ export const TableStoreV2 = ServiceStore.named('TableStoreV2')
const key = keyField || 'children';
let arr: Array<SRowV2> = rows.map((item, index) => {
let arr: Array<SRow2> = rows.map((item, index) => {
let id = getEntryId ? getEntryId(item, index) : guid();
return {
id: id,
key: String(`${index}-1-${index}`),
name: String(`${index}-1-${index}`),
index: index,
newIndex: index,
pristine: item,
@ -739,7 +739,7 @@ export const TableStoreV2 = ServiceStore.named('TableStoreV2')
const key =
location.pathname +
self.path +
self.toggableColumns.map(item => item.key || item.index).join('-');
self.toggableColumns.map(item => item.name || item.index).join('-');
const data = localStorage.getItem(key);
@ -755,5 +755,5 @@ export const TableStoreV2 = ServiceStore.named('TableStoreV2')
};
});
export type ITableStoreV2 = Instance<typeof TableStoreV2>;
export type STableStoreV2 = SnapshotIn<typeof TableStoreV2>;
export type ITableStore2 = Instance<typeof TableStore2>;
export type STableStore2 = SnapshotIn<typeof TableStore2>;

View File

@ -1,4 +1,4 @@
.#{$ns}Table-v2 {
.#{$ns}Table2 {
position: relative;
border-radius: var(--Table-borderRadius);

View File

@ -50,7 +50,7 @@
@import '../components/crud';
@import '../components/crud2';
@import '../components/table';
@import '../components/table-v2';
@import '../components/table2';
@import '../components/column-toggler';
@import '../components/list';
@import '../components/cards';

View File

@ -5,7 +5,13 @@
import React from 'react';
import {themeable, ThemeProps, LocaleProps, localeable} from 'amis-core';
import {
themeable,
ThemeProps,
LocaleProps,
localeable,
ClassNamesFn
} from 'amis-core';
import {ColumnProps} from './index';
const zIndex = 1;
@ -23,6 +29,7 @@ export interface Props extends ThemeProps, LocaleProps {
wrapperComponent: any;
groupId?: string; // 表头分组随机生成的id
depth?: number; // 表头分组
classnames: ClassNamesFn;
}
export class BodyCell extends React.Component<Props> {

View File

@ -6,10 +6,15 @@
import React from 'react';
import {findDOMNode} from 'react-dom';
import {themeable, ThemeProps, LocaleProps, localeable} from 'amis-core';
import {Overlay} from 'amis-core';
import {PopOver} from 'amis-core';
import {
themeable,
ThemeProps,
LocaleProps,
localeable,
ClassNamesFn,
Overlay,
PopOver
} from 'amis-core';
export interface FilterPayload {
closeDropdown?: boolean;
@ -31,6 +36,8 @@ export interface Props extends ThemeProps, LocaleProps {
filterDropdown: (payload: FilterDropdownProps) => JSX.Element | null; // 菜单内容
selectedKeys?: Array<string | number> | string;
setSelectedKeys?: (keys: Array<string | number> | string) => void;
classnames: ClassNamesFn;
classPrefix: string;
}
export interface State {

View File

@ -7,8 +7,13 @@ import React from 'react';
import {findDOMNode} from 'react-dom';
import isEqual from 'lodash/isEqual';
import {themeable, ThemeProps} from 'amis-core';
import {LocaleProps, localeable} from 'amis-core';
import {
themeable,
ThemeProps,
ClassNamesFn,
LocaleProps,
localeable
} from 'amis-core';
import HeadCellDropDown, {
FilterDropdownProps,
FilterPayload
@ -23,6 +28,8 @@ export interface Props extends ThemeProps, LocaleProps {
filteredValue?: Array<string>;
filterMultiple?: boolean;
popOverContainer?: () => Element | Text | null;
classnames: ClassNamesFn;
classPrefix: string;
}
export interface OptionProps {
@ -111,7 +118,7 @@ export class HeadCellFilter extends React.Component<Props, State> {
<li key={index}>
<CheckBox
classPrefix={ns}
onChange={e =>
onChange={(e: any) =>
this.handleCheck(
confirm,
setSelectedKeys,
@ -177,11 +184,11 @@ export class HeadCellFilter extends React.Component<Props, State> {
selectedKeys?: Array<string>
) {
const {onFilter, column} = this.props;
const payload = {[column.key]: selectedKeys};
const payload = {[column.name]: selectedKeys};
if (onFilter) {
const prevented = await onFilter({
filterName: column.key,
filterName: column.name,
filterValue: selectedKeys?.join(',')
});
if (prevented) {
@ -215,7 +222,7 @@ export class HeadCellFilter extends React.Component<Props, State> {
handleConfirmClick(confirm: (payload?: FilterPayload) => void) {
const {onFilter, column} = this.props;
onFilter && onFilter({[column.key]: this.state.filteredValue});
onFilter && onFilter({[column.name]: this.state.filteredValue});
confirm();
}

View File

@ -6,9 +6,17 @@
import React from 'react';
import {findDOMNode} from 'react-dom';
import {themeable, ThemeProps} from 'amis-core';
import {LocaleProps, localeable} from 'amis-core';
import HeadCellDropDown, {FilterPayload} from './HeadCellDropDown';
import {
themeable,
ThemeProps,
ClassNamesFn,
LocaleProps,
localeable
} from 'amis-core';
import HeadCellDropDown, {
FilterPayload,
FilterDropdownProps
} from './HeadCellDropDown';
import {RowSelectionOptionProps} from './index';
import {Icon} from '../icons';
@ -16,6 +24,8 @@ export interface Props extends ThemeProps, LocaleProps {
selections: Array<RowSelectionOptionProps>;
keys: Array<string | number> | string;
popOverContainer?: () => Element | Text | null;
classnames: ClassNamesFn;
classPrefix: string;
}
export interface State {
@ -58,7 +68,7 @@ export class HeadCellSelect extends React.Component<Props, State> {
selectedKeys,
confirm,
clearFilters
}) => {
}: FilterDropdownProps) => {
return (
<ul className={cx('DropDown-menu')}>
{selections.map((item, index) => (
@ -75,7 +85,9 @@ export class HeadCellSelect extends React.Component<Props, State> {
</ul>
);
}}
setSelectedKeys={keys => this.setState({key: keys})}
setSelectedKeys={(keys: Array<string | number> | string) =>
this.setState({key: keys})
}
selectedKeys={this.state.key}
></HeadCellDropDown>
);

View File

@ -5,13 +5,20 @@
import React from 'react';
import {themeable, ThemeProps} from 'amis-core';
import {LocaleProps, localeable} from 'amis-core';
import {
themeable,
ThemeProps,
ClassNamesFn,
LocaleProps,
localeable
} from 'amis-core';
import {Icon} from '../icons';
import {ColumnProps} from './index';
export interface Props extends ThemeProps, LocaleProps {
column: any;
column: ColumnProps;
onSort?: Function;
classnames: ClassNamesFn;
}
export interface State {
@ -37,7 +44,7 @@ export class HeadCellSort extends React.Component<Props, State> {
className={cx('TableCell-sortBtn')}
onClick={async () => {
let sortPayload = {};
if (column.key === this.state.orderBy) {
if (column.name === this.state.orderBy) {
if (this.state.order === 'descend') {
// 降序改为取消
sortPayload = {orderBy: '', order: 'ascend'};
@ -47,7 +54,7 @@ export class HeadCellSort extends React.Component<Props, State> {
}
} else {
// 默认先升序
sortPayload = {orderBy: column.key, order: 'ascend'};
sortPayload = {orderBy: column.name, order: 'ascend'};
}
if (onSort) {
@ -66,7 +73,7 @@ export class HeadCellSort extends React.Component<Props, State> {
<i
className={cx(
'TableCell-sortBtn--down',
this.state.orderBy === column.key && this.state.order === 'descend'
this.state.orderBy === column.name && this.state.order === 'descend'
? 'is-active'
: ''
)}
@ -76,7 +83,7 @@ export class HeadCellSort extends React.Component<Props, State> {
<i
className={cx(
'TableCell-sortBtn--up',
this.state.orderBy === column.key && this.state.order === 'ascend'
this.state.orderBy === column.name && this.state.order === 'ascend'
? 'is-active'
: ''
)}
@ -86,7 +93,7 @@ export class HeadCellSort extends React.Component<Props, State> {
<i
className={cx(
'TableCell-sortBtn--default',
this.state.orderBy === column.key ? '' : 'is-active'
this.state.orderBy === column.name ? '' : 'is-active'
)}
>
<Icon icon="sort-default" className="icon" />

View File

@ -12,9 +12,17 @@ import filter from 'lodash/filter';
import intersection from 'lodash/intersection';
import Sortable from 'sortablejs';
import {themeable, ClassNamesFn, ThemeProps} from 'amis-core';
import {localeable, LocaleProps} from 'amis-core';
import {isObject, isBreakpoint, guid, autobind} from 'amis-core';
import {
themeable,
ClassNamesFn,
ThemeProps,
localeable,
LocaleProps,
isObject,
isBreakpoint,
guid,
autobind
} from 'amis-core';
import {Icon} from '../icons';
import CheckBox from '../Checkbox';
import Spinner from '../Spinner';
@ -27,7 +35,7 @@ import Cell from './Cell';
export interface ColumnProps {
title: string | React.ReactNode | Function;
key: string;
name: string;
className?: Function;
children?: Array<ColumnProps>;
render: Function;
@ -1055,13 +1063,13 @@ export class Table extends React.PureComponent<TableProps, TableState> {
// th的最后一行才可调整列宽
// 分组情况下 最后一行才和列配置个数对应
// 就可以根据index找到col 不依赖key
// 就可以根据index找到col 不依赖name
const noChildren = !item.children?.length;
let cIndex = -1;
if (noChildren) {
// 根据key去tdColumns匹配出index
// 没设置key的 那一定不是要绑定数据的列 一般都是分组的上层 也不会出现调整列宽
cIndex = tdColumns.findIndex(c => c.key === item.key);
// 根据name去tdColumns匹配出index
// 没设置name的 那一定不是要绑定数据的列 一般都是分组的上层 也不会出现调整列宽
cIndex = tdColumns.findIndex(c => c.name === item.name);
}
const children = !item.children?.length ? (
<span>
@ -1390,7 +1398,7 @@ export class Table extends React.PureComponent<TableProps, TableState> {
const cells = tdColumns.map((item, i) => {
const render =
item.render && typeof item.render === 'function'
? item.render(data[item.key], data, rowIndex, i)
? item.render(data[item.name], data, rowIndex, i)
: null;
let props = {rowSpan: 1, colSpan: 1};
let children = render;
@ -1430,7 +1438,7 @@ export class Table extends React.PureComponent<TableProps, TableState> {
{i === 0 && hasChildrenRow
? this.getExpandedIcons(isExpanded, data)
: null}
{render ? children : data[item.key]}
{render ? children : data[item.name]}
</div>
</Cell>
);
@ -1516,7 +1524,7 @@ export class Table extends React.PureComponent<TableProps, TableState> {
type={rowSelection.type || 'checkbox'}
partial={!isRadio && hasChildrenChecked && !isChecked}
checked={isRadio ? isChecked : hasChildrenChecked || isChecked}
onChange={(value, shift) => {
onChange={(value: boolean) => {
if (!(rowSelection && rowSelection.rowClick)) {
this.selectedSingleRow(value, data);
}
@ -1944,7 +1952,7 @@ export class Table extends React.PureComponent<TableProps, TableState> {
return (
<div
ref={this.tableDom}
className={cx('Table-v2', className, {
className={cx('Table2', className, {
[cx('Table-scroll-horizontal')]: hasScrollX,
[cx(`Table-${size}`)]: size,
[cx('Table-bordered')]: bordered,

View File

@ -119,7 +119,7 @@ import {TransferPickerControlSchema} from './renderers/Form/TransferPicker';
import {TabsTransferPickerControlSchema} from './renderers/Form/TabsTransferPicker';
import {UserSelectControlSchema} from './renderers/Form/UserSelect';
import {JSONSchemaEditorControlSchema} from './renderers/Form/JSONSchemaEditor';
import {TableSchemaV2} from './renderers/Table-v2';
import {TableSchema2} from './renderers/Table2';
import {
BaseSchemaWithoutType,
FormBaseControl,
@ -212,7 +212,7 @@ export type SchemaType =
| 'switch'
| 'table'
| 'static-table' // 这个几个跟表单项同名再form下面用必须带前缀 static-
| 'table-v2'
| 'table2'
| 'tabs'
| 'html'
| 'tpl'
@ -407,7 +407,7 @@ export type SchemaObject =
| StatusSchema
| SpinnerSchema
| TableSchema
| TableSchemaV2
| TableSchema2
| TabsSchema
| TasksSchema
| VBoxSchema

View File

@ -143,7 +143,7 @@ import './renderers/WebComponent';
import './renderers/GridNav';
import './renderers/TooltipWrapper';
import './renderers/Tag';
import './renderers/Table-v2/index';
import './renderers/Table2/index';
import './compat';
import './schemaExtend';

View File

@ -35,7 +35,7 @@ import {
} from '../Schema';
import {CardsSchema} from './Cards';
import {ListSchema} from './List';
import {TableSchema} from './Table';
import {TableSchema2} from './Table2';
import {isPureVariable, resolveVariableAndFilter} from 'amis-core';
import {SchemaCollection} from '../Schema';
import {upperFirst} from 'lodash';
@ -51,7 +51,7 @@ export interface CRUD2CommonSchema extends BaseSchema {
/**
*
*/
mode?: 'table' | 'grid' | 'cards' | /* grid 的别名*/ 'list' | 'table-v2';
mode?: 'table' | 'grid' | 'cards' | /* grid 的别名*/ 'list' | 'table2';
/**
* API
@ -183,8 +183,8 @@ export type CRUD2ListSchema = CRUD2CommonSchema & {
} & Omit<ListSchema, 'type'>;
export type CRUD2TableSchema = CRUD2CommonSchema & {
mode?: 'table-v2';
} & Omit<TableSchema, 'type'>;
mode?: 'table2';
} & Omit<TableSchema2, 'type'>;
export type CRUD2Schema = CRUD2CardsSchema | CRUD2ListSchema | CRUD2TableSchema;
@ -281,7 +281,7 @@ export default class CRUD2 extends React.Component<CRUD2Props, any> {
// 自定义列需要用store里的数据同步显示列
// 所以需要先初始化一下
const {mode, columns} = props;
if (mode === 'table-v2' && columns) {
if (mode === 'table2' && columns) {
store.updateColumns(columns);
}
}
@ -308,7 +308,9 @@ export default class CRUD2 extends React.Component<CRUD2Props, any> {
componentDidUpdate(prevProps: CRUD2Props) {
const props = this.props;
const store = prevProps.store;
if (prevProps.columns !== props.columns) {
store.updateColumns(props.columns);
}
// picker外部引起的值变化处理
let val: any;
if (
@ -532,7 +534,7 @@ export default class CRUD2 extends React.Component<CRUD2Props, any> {
loadDataMode,
syncResponse2Query,
columns: store.columns ?? columns,
isTableV2: true
isTable2: true
})
.then(value => {
interval &&
@ -1085,7 +1087,7 @@ export default class CRUD2 extends React.Component<CRUD2Props, any> {
filter,
render,
store,
mode = 'table-v2',
mode = 'table2',
syncLocation,
children,
bulkActions,

View File

@ -18,7 +18,7 @@ import {generateIcon} from 'amis-core';
import {RootClose} from 'amis-core';
import type {TooltipObject} from 'amis-ui/lib/components/TooltipWrapper';
import {IColumn} from 'amis-core/lib/store/table';
import type {IColumnV2} from 'amis-core/lib/store/table-v2';
import type {IColumn2} from 'amis-core/lib/store/table2';
export interface ColumnTogglerProps extends RendererProps {
/**
@ -114,14 +114,14 @@ export interface ColumnTogglerProps extends RendererProps {
/**
*
*/
columns: Array<IColumn | IColumnV2>;
columns: Array<IColumn | IColumn2>;
/**
*
*/
footerBtnSize?: 'xs' | 'sm' | 'md' | 'lg';
activeToggaleColumns: Array<IColumn | IColumnV2>;
activeToggaleColumns: Array<IColumn | IColumn2>;
onColumnToggle: (columns: Array<IColumn>) => void;
modalContainer?: () => HTMLElement;
}

View File

@ -1,12 +1,8 @@
import React from 'react';
import {
Renderer,
createObject,
isVisible
} from 'amis-core';
import {Renderer, createObject, isVisible, ClassNamesFn} from 'amis-core';
import {Checkbox} from 'amis-ui';
import ColumnToggler, {ColumnTogglerProps} from '../Table/ColumnToggler';
import { BaseSchema } from '../../Schema';
import {BaseSchema} from '../../Schema';
export interface ColumnTogglerSchema extends BaseSchema {
label?: string;
@ -21,6 +17,8 @@ export interface ColumnTogglerRendererProps extends ColumnTogglerProps {
toggleAllColumns?: Function;
toggleToggle?: Function;
cols: Array<any>;
classnames: ClassNamesFn;
classPrefix: string;
}
@Renderer({
@ -51,9 +49,13 @@ export class ColumnTogglerRenderer extends React.Component<ColumnTogglerRenderer
}
const toggableColumns = cols.filter(
(item: any) => isVisible(item.pristine || item, data) && item.toggable !== false);
(item: any) =>
isVisible(item.pristine || item, data) && item.toggable !== false
);
const activeToggaleColumns = toggableColumns.filter((item: any) => item.toggled !== false);
const activeToggaleColumns = toggableColumns.filter(
(item: any) => item.toggled !== false
);
return (
<ColumnToggler
@ -80,8 +82,7 @@ export class ColumnTogglerRenderer extends React.Component<ColumnTogglerRenderer
const {data, dispatchEvent} = this.props;
const allToggled = !(
activeToggaleColumns?.length ===
toggableColumns?.length
activeToggaleColumns?.length === toggableColumns?.length
);
const rendererEvent = await dispatchEvent(
'columnToggled',
@ -126,7 +127,7 @@ export class ColumnTogglerRenderer extends React.Component<ColumnTogglerRenderer
if (column.toggled !== false) {
columns.push(column);
} else {
columns = columns.filter((c: any) => c.key !== column.key);
columns = columns.filter((c: any) => c.name !== column.name);
}
const rendererEvent = await dispatchEvent(
'columnToggled',
@ -138,11 +139,14 @@ export class ColumnTogglerRenderer extends React.Component<ColumnTogglerRenderer
if (rendererEvent?.prevented) {
return;
}
toggleToggle && toggleToggle(!(column.toggled !== false), index);
}}
>
<Checkbox size="sm" classPrefix={ns} checked={column.toggled !== false}>
<Checkbox
size="sm"
classPrefix={ns}
checked={column.toggled !== false}
>
{column.title ? render('tpl', column.title) : null}
</Checkbox>
</li>

View File

@ -1,12 +1,15 @@
import React from 'react';
import {findDOMNode} from 'react-dom';
import {RendererProps} from 'amis-core';
import {ActionObject} from 'amis-core';
import {Icon} from 'amis-ui';
import {setVariable, createObject} from 'amis-core';
import {ITableStoreV2} from 'amis-core';
import {HeadCellDropDown} from 'amis-ui';
import {
RendererProps,
ActionObject,
setVariable,
createObject,
ITableStore2,
ClassNamesFn
} from 'amis-core';
import {Icon, HeadCellDropDown} from 'amis-ui';
import type {FilterDropdownProps} from 'amis-ui/lib/components/table/HeadCellDropDown';
export interface QuickSearchConfig {
@ -20,10 +23,16 @@ export interface QuickSearchConfig {
export interface HeadCellSearchProps extends RendererProps {
name: string;
searchable: boolean | QuickSearchConfig;
classPrefix: string;
onSearch?: (values: object) => void;
onAction?: Function;
store: ITableStoreV2;
store: ITableStore2;
sortable: boolean;
label: string;
orderBy: string;
orderDir: string;
popOverContainer?: any;
classnames: ClassNamesFn;
classPrefix: string;
}
export class HeadCellSearchDropDown extends React.Component<
@ -273,9 +282,7 @@ export class HeadCellSearchDropDown extends React.Component<
...data,
orderBy,
order:
orderBy && orderBy === name
? (store as ITableStoreV2).order
: ''
orderBy && orderBy === name ? (store as ITableStore2).order : ''
},
onSubmit: (values: object) => this.handleSubmit(values, confirm),
onAction: (e: any, action: ActionObject, ctx: object) => {

View File

@ -4,38 +4,53 @@ import {isAlive} from 'mobx-state-tree';
import cloneDeep from 'lodash/cloneDeep';
import isEqual from 'lodash/isEqual';
import {ScopedContext, IScopedContext} from 'amis-core';
import {Renderer, RendererProps} from 'amis-core';
import {ActionObject} from 'amis-core';
import {Icon, Table, Spinner} from 'amis-ui';
import {BaseSchema, SchemaObject, SchemaTokenizeableString} from '../../Schema';
import {
ScopedContext,
IScopedContext,
Renderer,
RendererProps,
ActionObject,
isObject,
anyChanged,
difference,
createObject,
autobind
} from 'amis-core';
import {
autobind,
resolveVariableAndFilter,
isPureVariable,
resolveVariable
resolveVariable,
evalExpression,
filter,
isEffectiveApi,
TableStore2,
ITableStore2,
IRow2,
ClassNamesFn
} from 'amis-core';
import {evalExpression, filter} from 'amis-core';
import {isEffectiveApi} from 'amis-core';
import {Checkbox} from 'amis-ui';
import {BadgeObject} from 'amis-ui';
import {TableStoreV2, ITableStoreV2, IColumnV2, IRowV2} from 'amis-core';
import {Icon, Table, Spinner, BadgeObject} from 'amis-ui';
import type {
SortProps,
ColumnProps,
RowSelectionProps,
ExpandableProps,
OnRowProps,
SummaryProps
} from 'amis-ui/lib/components/table';
import {
BaseSchema,
SchemaObject,
SchemaTokenizeableString,
SchemaApi,
SchemaMessage
} from '../../Schema';
import {ActionSchema} from '../Action';
import {HeadCellSearchDropDown} from './HeadCellSearchDropdown';
import './TableCell';
import './ColumnToggler';
import type {SortProps} from 'amis-ui/lib/components/table';
import {Action} from '../../types';
/**
* Table v2渲染器
* https://baidu.gitee.io/amis/docs/components/table-v2
* Table 2
* https://baidu.gitee.io/amis/docs/components/table2
*/
export interface CellSpan {
@ -54,7 +69,7 @@ export interface ColumnSchema {
/**
*
*/
key: string;
name: string;
/**
*
@ -218,11 +233,11 @@ export interface ExpandableSchema {
expandedRowKeysExpr: string;
}
export interface TableSchemaV2 extends BaseSchema {
export interface TableSchema2 extends BaseSchema {
/**
*
*/
type: 'table-v2';
type: 'table2';
/**
*
@ -265,10 +280,15 @@ export interface TableSchemaV2 extends BaseSchema {
loading?: boolean | string | SchemaObject;
/**
*
*
*/
itemBadge?: BadgeObject;
/**
*
*/
showBadge?: boolean;
/**
* dom
*/
@ -313,9 +333,39 @@ export interface TableSchemaV2 extends BaseSchema {
*
*/
footer?: string | SchemaObject | Array<SchemaObject>;
/**
* API
*/
quickSaveApi?: SchemaApi;
/**
* 使 API
*/
quickSaveItemApi?: SchemaApi;
/**
*
*/
primaryField?: string;
/**
*
*/
messages?: SchemaMessage;
/**
*
*/
reload?: string;
/**
*
*/
actions?: Array<ActionSchema>;
}
export type TableV2RendererEvent =
export type Table2RendererEvent =
| 'selected'
| 'columnSort'
| 'columnFilter'
@ -323,22 +373,39 @@ export type TableV2RendererEvent =
| 'columnToggled'
| 'dragOver';
export type TableV2RendererAction = 'selectAll' | 'clearAll' | 'select';
export type Table2RendererAction = 'selectAll' | 'clearAll' | 'select';
export interface TableV2Props extends RendererProps {
export interface Table2Props extends RendererProps, Omit<TableSchema2, 'type'> {
title?: string;
source?: string;
store: ITableStoreV2;
togglable: boolean;
columns: Array<ColumnSchema | ColumnProps>;
onSelect?: Function;
reUseRow?: boolean;
getEntryId?: Function;
store: ITableStore2;
rowSelection?: RowSelectionSchema | RowSelectionProps;
expandable?: ExpandableSchema | ExpandableProps;
classnames: ClassNamesFn;
onSave?: Function;
onSaveOrder?: Function;
onPristineChange?: Function;
onAction?: Function;
onSort?: Function;
onFilter?: Function;
onRow?: OnRowProps;
placeholder?: string | SchemaObject;
itemActions?: Array<ActionObject>;
headSummary?: Array<SummaryProps | Array<SummaryProps>>;
footSummary?: Array<SummaryProps | Array<SummaryProps>>;
headingClassName?: string;
}
export default class TableV2 extends React.Component<TableV2Props, object> {
export default class Table2 extends React.Component<Table2Props, object> {
static contextType = ScopedContext;
renderedToolbars: Array<string> = [];
control: any;
constructor(props: TableV2Props, context: IScopedContext) {
constructor(props: Table2Props, context: IScopedContext) {
super(props);
const scoped = context;
@ -347,7 +414,7 @@ export default class TableV2 extends React.Component<TableV2Props, object> {
const {store, columnsTogglable, columns} = props;
store.update({columnsTogglable, columns});
TableV2.syncRows(store, props, undefined) && this.syncSelected();
Table2.syncRows(store, props, undefined) && this.syncSelected();
}
componentWillUnmount() {
@ -370,15 +437,15 @@ export default class TableV2 extends React.Component<TableV2Props, object> {
onSelect &&
onSelect(
store.selectedRows.map(item => item.data),
store.unSelectedRows.map(item => item.data)
store.selectedRows.map((item: IRow2) => item.data),
store.unSelectedRows.map((item: IRow2) => item.data)
);
}
static syncRows(
store: ITableStoreV2,
props: TableV2Props,
prevProps?: TableV2Props
store: ITableStore2,
props: Table2Props,
prevProps?: Table2Props
) {
const source = props.source;
const value = props.value || props.items;
@ -454,7 +521,7 @@ export default class TableV2 extends React.Component<TableV2Props, object> {
return updateRows;
}
componentDidUpdate(prevProps: TableV2Props) {
componentDidUpdate(prevProps: Table2Props) {
const props = this.props;
const store = props.store;
@ -471,7 +538,7 @@ export default class TableV2 extends React.Component<TableV2Props, object> {
(props.data !== prevProps.data ||
(typeof props.source === 'string' && isPureVariable(props.source))))
) {
TableV2.syncRows(store, props, prevProps) && this.syncSelected();
Table2.syncRows(store, props, prevProps) && this.syncSelected();
}
if (!isEqual(prevProps.columns, props.columns)) {
@ -493,7 +560,7 @@ export default class TableV2 extends React.Component<TableV2Props, object> {
if (schema && isObject(schema)) {
// 在TableCell里会根据width设置div的width
// 原来的table td/th是最外层标签 设置width没问题
// v2的拆开了 就不需要再设置div的width了
// table2的拆开了 就不需要再设置div的width了
// 否则加上padding 就超出单元格的区域了
// children属性在schema里是一个关键字 在渲染器schema中 自定义的children没有用 去掉
const {width, children, ...rest} = schema;
@ -504,7 +571,7 @@ export default class TableV2 extends React.Component<TableV2Props, object> {
type: 'cell-field',
column: rest,
data: props.data,
name: schema.key
name: schema.name
},
props
);
@ -616,12 +683,12 @@ export default class TableV2 extends React.Component<TableV2Props, object> {
const obj = {
children: this.renderCellSchema(column, {
data: item.locals,
value: column.key
value: column.name
? resolveVariable(
column.key,
column.name,
canAccessSuperData ? item.locals : item.data
)
: column.key,
: column.name,
popOverContainer:
popOverContainer || this.getPopOverContainer,
onQuickChange: (
@ -709,7 +776,7 @@ export default class TableV2 extends React.Component<TableV2Props, object> {
<HeadCellSearchDropDown
{...this.props}
popOverContainer={this.getPopOverContainer}
name={column.key}
name={column.name}
searchable={column.searchable}
orderBy={store.orderBy}
orderDir={store.order}
@ -730,7 +797,7 @@ export default class TableV2 extends React.Component<TableV2Props, object> {
return cols;
}
buildSummary(key: string, summary: Array<any>) {
buildSummary(key: string, summary?: Array<any>) {
const result: Array<any> = [];
if (Array.isArray(summary)) {
summary.forEach((s, index) => {
@ -790,7 +857,7 @@ export default class TableV2 extends React.Component<TableV2Props, object> {
if (Array.isArray(rows)) {
if (!isEffectiveApi(quickSaveApi)) {
env && env.alert('TableV2 quickSaveApi is required');
env && env.alert('Table2 quickSaveApi is required');
return;
}
@ -822,7 +889,7 @@ export default class TableV2 extends React.Component<TableV2Props, object> {
.catch(() => {});
} else {
if (!isEffectiveApi(quickSaveItemApi)) {
env && env.alert('TableV2 quickSaveItemApi is required!');
env && env.alert('Table2 quickSaveItemApi is required!');
return;
}
@ -846,7 +913,7 @@ export default class TableV2 extends React.Component<TableV2Props, object> {
@autobind
handleQuickChange(
item: IRowV2,
item: IRow2,
values: object,
saveImmediately?: boolean | any,
savePristine?: boolean,
@ -870,14 +937,15 @@ export default class TableV2 extends React.Component<TableV2Props, object> {
}
if (saveImmediately && saveImmediately.api) {
this.props.onAction(
null,
{
actionType: 'ajax',
api: saveImmediately.api
},
values
);
this.props.onAction &&
this.props.onAction(
null,
{
actionType: 'ajax',
api: saveImmediately.api
},
values
);
return;
}
@ -905,7 +973,7 @@ export default class TableV2 extends React.Component<TableV2Props, object> {
const {onAction} = this.props;
// todo
onAction(e, action, ctx);
onAction && onAction(e, action, ctx);
}
renderActions(region: string) {
@ -923,6 +991,7 @@ export default class TableV2 extends React.Component<TableV2Props, object> {
const isInCrud = /(?:\/|^)crud2\//.test($path as string);
actions = Array.isArray(actions) ? actions.concat() : [];
const config = isObject(columnsTogglable) ? columnsTogglable : {};
// 现在默认从crud里传进来的columnsTogglable是boolean类型
// table单独配置的是SchemaNode类型
@ -937,11 +1006,11 @@ export default class TableV2 extends React.Component<TableV2Props, object> {
children: render(
'column-toggler',
{
...(isObject(columnsTogglable) ? columnsTogglable : {}),
...config,
type: 'column-toggler'
},
{
cols: store.columnsData.map(item => item.pristine),
cols: store.columnsData,
toggleAllColumns: () => store.toggleAllColumns(),
toggleToggle: (toggled: boolean, index: number) => {
const column = store.columnsData[index];
@ -1067,8 +1136,10 @@ export default class TableV2 extends React.Component<TableV2Props, object> {
async handleSaveOrder() {
const {store, onSaveOrder, data, dispatchEvent} = this.props;
const movedItems = store.movedRows.map(item => item.data);
const items = store.rows.map(item => item.getDataWithModifiedChilden());
const movedItems = store.movedRows.map((item: IRow2) => item.data);
const items = store.rows.map((item: IRow2) =>
item.getDataWithModifiedChilden()
);
const rendererEvent = await dispatchEvent(
'orderChange',
@ -1133,7 +1204,6 @@ export default class TableV2 extends React.Component<TableV2Props, object> {
rowSelection,
columns,
expandable,
expandableBody,
footSummary,
headSummary,
loading,
@ -1363,12 +1433,12 @@ export default class TableV2 extends React.Component<TableV2Props, object> {
}
@Renderer({
type: 'table-v2',
storeType: TableStoreV2.name,
name: 'table-v2',
type: 'table2',
storeType: TableStore2.name,
name: 'table2',
isolateScope: true
})
export class TableRenderer extends TableV2 {
export class TableRenderer extends Table2 {
receive(values: any, subPath?: string) {
const scoped = this.context as IScopedContext;
const parents = scoped?.parent?.getComponents();