feat: CRUD & 与其搭配的 table,cards,list三种模式支持配置 affixFooter

This commit is contained in:
2betop 2023-12-21 15:10:09 +08:00
parent 50a74cee94
commit 467826aaa9
8 changed files with 121 additions and 37 deletions

View File

@ -207,12 +207,13 @@ CRUD 组件对数据源接口的数据结构要求如下:
`syncLocation`开启后CRUD 在初始化数据域时,将会对 url 中的 Query 进行转换,将原始类型的字符串格式的转化为同位类型。`3.6.0`版本后支持对象格式,该配置默认开启,且默认仅转化布尔值。
#### ParsePrimitiveQueryOptions
```typescript
interface ParsePrimitiveQueryOptions {
parsePrimitiveQuery: {
enable: boolean;
types?: ('boolean' | 'number')[]
}
types?: ('boolean' | 'number')[];
};
}
```
@ -2926,6 +2927,7 @@ interface CRUDMatchFunc {
#### 刷新 CRUD 触发方式
触发 CRUD 刷新的方式有 3 种:
1. **reload 类型按钮**:使用`{"type": "reload", ...}`CRUD 内部会对点击事件做处理
2. **reload 动作按钮**:使用`{"type": "action", "actionType": "reload", "target": "targetName", ...}`,指定`target`为要刷新的 CRUD 组件的`name`
3. **reload 事件动作**:使用[事件动作](../../docs/concepts/event-action),指定`id`为要刷新的 CRUD 组件的`id`
@ -3626,6 +3628,7 @@ itemAction 里的 onClick 还能通过 `data` 参数拿到当前行的数据,
| footerToolbar | Array | `['statistics', 'pagination']` | 底部工具栏配置 |
| alwaysShowPagination | `boolean` | `false` | 是否总是显示分页 |
| affixHeader | `boolean` | `true` | 是否固定表头(table 下) |
| affixFooter | `boolean` | `false` | 是否固定表格底部工具栏 |
| autoGenerateFilter | `Object \| boolean` | | 是否开启查询区域,开启后会根据列元素的 `searchable` 属性值,自动生成查询条件表单 |
| resetPageAfterAjaxItemAction | `boolean` | `false` | 单条数据 ajax 操作后是否重置页码为第一页 |
| autoFillHeight | `boolean``{height: number}` | | 内容区域自适应高度 |
@ -3633,7 +3636,6 @@ itemAction 里的 onClick 还能通过 `data` 参数拿到当前行的数据,
| matchFunc | `string` | [`CRUDMatchFunc`](#匹配函数) | 自定义匹配函数, 当开启`loadDataOnce`时,会基于该函数计算的匹配结果进行过滤,主要用于处理列字段类型较为复杂或者字段值格式和后端返回不一致的场景 | `3.5.0` |
| parsePrimitiveQuery | [`ParsePrimitiveQueryOptions`](#ParsePrimitiveQueryOptions) | `true` | 是否开启 Query 信息转换,开启后将会对 url 中的 Query 进行转换,默认开启,默认仅转化布尔值 | `3.6.0` |
注意除了上面这些属性CRUD 在不同模式下的属性需要参考各自的文档,比如
- 默认[Table](./table)模式里的[列配置](./table#列配置属表)。

View File

@ -1832,6 +1832,7 @@ popOver 的其它配置请参考 [popover](./popover)
| source | `string` | `${items}` | 数据源, 绑定当前环境变量 | |
| deferApi | [API](../../docs/types/api) | | 当行数据中有 defer 属性时,用此接口进一步加载内容 |
| affixHeader | `boolean` | `true` | 是否固定表头 | |
| affixFooter | `boolean` | `false` | 是否固定表格底部工具栏 | |
| columnsTogglable | `auto` 或者 `boolean` | `auto` | 展示列显示开关, 自动即:列数量大于或等于 5 个时自动开启 | |
| placeholder | `string` 或者 `SchemaTpl` | `暂无数据` | 当没数据的时候的文字提示 | |
| className | `string` | `panel-default` | 外层 CSS 类名 | |

View File

@ -1,7 +1,8 @@
.#{$ns}Cards {
&-toolbar {
@include clearfix();
margin: 0 var(--Cards-toolbar-marginX) var(--Cards-toolbar-marginY);
padding: var(--Cards-toolbar-marginY) var(--Cards-toolbar-marginX)
var(--Cards-toolbar-marginY);
}
&-actions {
@ -95,6 +96,14 @@
flex: unset;
}
}
&-footToolbar--affix,
&-footer--affix {
position: sticky;
bottom: var(--affix-offset-bottom);
background: var(--Table-bg);
z-index: $zindex-sticky;
}
}
@include media-breakpoint-up(sm) {

View File

@ -12,7 +12,8 @@
@include clearfix();
display: flex;
flex-wrap: wrap;
margin: 0 var(--List-toolbar-marginX) var(--List-toolbar-marginY);
padding: var(--List-toolbar-marginY) var(--List-toolbar-marginX)
var(--List-toolbar-marginY);
}
&-actions {
@ -78,6 +79,14 @@
min-height: var(--List-placeholder-height);
line-height: var(--List-placeholder-height);
}
&-footToolbar--affix,
&-footer--affix {
position: sticky;
bottom: var(--affix-offset-bottom);
background: var(--Table-bg);
z-index: $zindex-sticky;
}
}
.#{$ns}ListGroup {

View File

@ -143,6 +143,14 @@
}
}
&-footerToolbar--affix,
&-footer--affix {
position: sticky;
bottom: var(--affix-offset-bottom);
background: var(--Table-bg);
z-index: $zindex-sticky;
}
&.is-mobile {
.#{$ns}Table-toolbar {
.#{$ns}Form-item {

View File

@ -104,6 +104,11 @@ export interface CardsSchema extends BaseSchema, SpinnerExtraProps {
*/
affixHeader?: boolean;
/**
*
*/
affixFooter?: boolean;
/**
*
*/
@ -735,7 +740,8 @@ export default class Cards extends React.Component<GridProps, object> {
render,
showFooter,
store,
classnames: cx
classnames: cx,
affixFooter
} = this.props;
if (showFooter === false) {
@ -755,18 +761,33 @@ export default class Cards extends React.Component<GridProps, object> {
: null;
const actions = this.renderActions('footer');
const footerNode = footer ? (
<div
className={cx(
'Cards-footer',
footerClassName,
affixFooter ? 'Cards-footer--affix' : ''
)}
key="footer"
>
{render('footer', footer)}
</div>
) : null;
const toolbarNode =
actions || child ? (
<div className={cx('Cards-toolbar')} key="footer-toolbar">
<div
className={cx(
'Cards-toolbar',
!footerNode && affixFooter ? 'Cards-footToolbar--affix' : ''
)}
key="footer-toolbar"
>
{actions}
{child}
</div>
) : null;
const footerNode = footer ? (
<div className={cx('Cards-footer', footerClassName)} key="footer">
{render('footer', footer)}
</div>
) : null;
return footerNode && toolbarNode
? [toolbarNode, footerNode]
: footerNode || toolbarNode || null;

View File

@ -202,6 +202,11 @@ export interface ListSchema extends BaseSchema {
*/
affixHeader?: boolean;
/**
*
*/
affixFooter?: boolean;
/**
*
*/
@ -810,7 +815,8 @@ export default class List extends React.Component<ListProps, object> {
render,
showFooter,
store,
classnames: cx
classnames: cx,
affixFooter
} = this.props;
if (showFooter === false) {
@ -830,22 +836,35 @@ export default class List extends React.Component<ListProps, object> {
: null;
const actions = this.renderActions('footer');
const footerNode =
footer && (!Array.isArray(footer) || footer.length) ? (
<div
className={cx(
'List-footer',
footerClassName,
affixFooter ? 'List-footer--affix' : ''
)}
key="footer"
>
{render('footer', footer)}
</div>
) : null;
const toolbarNode =
actions || child ? (
<div
className={cx('List-toolbar', footerClassName)}
className={cx(
'List-toolbar',
footerClassName,
!footerNode && affixFooter ? 'List-footToolbar--affix' : ''
)}
key="footer-toolbar"
>
{actions}
{child}
</div>
) : null;
const footerNode =
footer && (!Array.isArray(footer) || footer.length) ? (
<div className={cx('List-footer', footerClassName)} key="footer">
{render('footer', footer)}
</div>
) : null;
return footerNode && toolbarNode
? [toolbarNode, footerNode]
: footerNode || toolbarNode || null;

View File

@ -222,6 +222,11 @@ export interface TableSchema extends BaseSchema {
*/
affixHeader?: boolean;
/**
*
*/
affixFooter?: boolean;
/**
*
*/
@ -2544,7 +2549,8 @@ export default class Table extends React.Component<TableProps, object> {
showFooter,
store,
data,
classnames: cx
classnames: cx,
affixFooter
} = this.props;
if (showFooter === false) {
@ -2564,13 +2570,30 @@ export default class Table extends React.Component<TableProps, object> {
: null;
const actions = this.renderActions('footer');
const footerNode =
footer && (!Array.isArray(footer) || footer.length) ? (
<div
className={cx(
'Table-footer',
footerClassName,
affixFooter ? 'Table-footer--affix' : ''
)}
key="footer"
>
{render('footer', footer, {
data: store.getData(data)
})}
</div>
) : null;
const toolbarNode =
actions || child ? (
<div
className={cx(
'Table-toolbar Table-footToolbar',
toolbarClassName,
footerToolbarClassName
footerToolbarClassName,
!footerNode && affixFooter ? 'Table-footToolbar--affix' : ''
)}
key="footer-toolbar"
>
@ -2578,14 +2601,6 @@ export default class Table extends React.Component<TableProps, object> {
{child}
</div>
) : null;
const footerNode =
footer && (!Array.isArray(footer) || footer.length) ? (
<div className={cx('Table-footer', footerClassName)} key="footer">
{render('footer', footer, {
data: store.getData(data)
})}
</div>
) : null;
return footerNode && toolbarNode
? [toolbarNode, footerNode]
: footerNode || toolbarNode || null;