feat: 新增maxItemSelectionLength支持单独配置当前页最大勾选数 (#9249)

Co-authored-by: wanglinfang <wanglinfang@baidu.com>
This commit is contained in:
wanglinfang2014 2024-01-08 20:57:24 +08:00 committed by GitHub
parent f663be714d
commit fba3074311
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 248 additions and 80 deletions

View File

@ -2060,75 +2060,220 @@ interface CRUDMatchFunc {
**保留条目选择**
默认分页、搜后,用户选择条目会被清空,配置`keepItemSelectionOnPageChange`属性后会保留用户选择,可以实现跨页面批量操作。
默认分页、搜后,用户选择条目会被清空,配置`keepItemSelectionOnPageChange`属性后会保留用户选择,可以实现跨页面批量操作。
同时可以通过配置`maxKeepItemSelectionLength`属性限制最大勾选数
```schema: scope="body"
{
"type": "crud",
"syncLocation": false,
"api": "/api/mock2/sample",
"headerToolbar": [
"bulkActions"
],
"keepItemSelectionOnPageChange": true,
"maxKeepItemSelectionLength": 4,
"bulkActions": [
{
"label": "批量删除",
"actionType": "ajax",
"api": "delete:/api/mock2/sample/${ids|raw}",
"confirmText": "确定要批量删除?"
},
{
"label": "批量修改",
"actionType": "dialog",
"dialog": {
"title": "批量编辑",
"body": {
"type": "form",
"api": "/api/mock2/sample/bulkUpdate2",
"body": [
{
"type": "hidden",
"name": "ids"
},
{
"type": "input-text",
"name": "engine",
"label": "Engine"
}
]
}
"type": "crud",
"syncLocation": false,
"api": "/api/mock2/sample",
"headerToolbar": [
"bulkActions"
],
"keepItemSelectionOnPageChange": true,
"maxKeepItemSelectionLength": 4,
"bulkActions": [
{
"label": "批量删除",
"actionType": "ajax",
"api": "delete:/api/mock2/sample/${ids|raw}",
"confirmText": "确定要批量删除?"
},
{
"label": "批量修改",
"actionType": "dialog",
"dialog": {
"title": "批量编辑",
"body": {
"type": "form",
"api": "/api/mock2/sample/bulkUpdate2",
"body": [
{
"type": "hidden",
"name": "ids"
},
{
"type": "input-text",
"name": "engine",
"label": "Engine"
}
]
}
],
"columns": [
{
"name": "id",
"label": "ID"
},
{
"name": "engine",
"label": "Rendering engine"
},
{
"name": "browser",
"label": "Browser"
},
{
"name": "platform",
"label": "Platform(s)"
},
{
"name": "version",
"label": "Engine version"
},
{
"name": "grade",
"label": "CSS grade"
}
}
],
"columns": [
{
"name": "id",
"label": "ID"
},
{
"name": "engine",
"label": "Rendering engine"
},
{
"name": "browser",
"label": "Browser"
},
{
"name": "platform",
"label": "Platform(s)"
},
{
"name": "version",
"label": "Engine version"
},
{
"name": "grade",
"label": "CSS grade"
}
]
}
```
**当前页最大勾选数**
如果不需要在分页、搜索后,保留用户选择,即不需要配置`keepItemSelectionOnPageChange`,可以通过配置`maxItemSelectionLength`属性限制当前页条目的最大勾选数
```schema: scope="body"
{
"type": "crud",
"syncLocation": false,
"api": "/api/mock2/sample",
"headerToolbar": [
"bulkActions"
],
"maxItemSelectionLength": 4,
"bulkActions": [
{
"label": "批量删除",
"actionType": "ajax",
"api": "delete:/api/mock2/sample/${ids|raw}",
"confirmText": "确定要批量删除?"
},
{
"label": "批量修改",
"actionType": "dialog",
"dialog": {
"title": "批量编辑",
"body": {
"type": "form",
"api": "/api/mock2/sample/bulkUpdate2",
"body": [
{
"type": "hidden",
"name": "ids"
},
{
"type": "input-text",
"name": "engine",
"label": "Engine"
}
]
}
]
}
}
],
"columns": [
{
"name": "id",
"label": "ID"
},
{
"name": "engine",
"label": "Rendering engine"
},
{
"name": "browser",
"label": "Browser"
},
{
"name": "platform",
"label": "Platform(s)"
},
{
"name": "version",
"label": "Engine version"
},
{
"name": "grade",
"label": "CSS grade"
}
],
"itemCheckableOn": "this.index !== 2"
}
```
`maxItemSelectionLength`也可以和`keepItemSelectionOnPageChange`搭配使用,起到和`maxKeepItemSelectionLength`一样的效果
```schema: scope="body"
{
"type": "crud",
"syncLocation": false,
"api": "/api/mock2/sample",
"headerToolbar": [
"bulkActions"
],
"keepItemSelectionOnPageChange": true,
"maxItemSelectionLength": 4,
"bulkActions": [
{
"label": "批量删除",
"actionType": "ajax",
"api": "delete:/api/mock2/sample/${ids|raw}",
"confirmText": "确定要批量删除?"
},
{
"label": "批量修改",
"actionType": "dialog",
"dialog": {
"title": "批量编辑",
"body": {
"type": "form",
"api": "/api/mock2/sample/bulkUpdate2",
"body": [
{
"type": "hidden",
"name": "ids"
},
{
"type": "input-text",
"name": "engine",
"label": "Engine"
}
]
}
}
}
],
"columns": [
{
"name": "id",
"label": "ID"
},
{
"name": "engine",
"label": "Rendering engine"
},
{
"name": "browser",
"label": "Browser"
},
{
"name": "platform",
"label": "Platform(s)"
},
{
"name": "version",
"label": "Engine version"
},
{
"name": "grade",
"label": "CSS grade"
}
],
"itemCheckableOn": "this.index !== 2 && this.index !== 5"
}
```
@ -3665,8 +3810,10 @@ itemAction 里的 onClick 还能通过 `data` 参数拿到当前行的数据,
| hideQuickSaveBtn | `boolean` | `false` | 隐藏顶部快速保存提示 |
| autoJumpToTopOnPagerChange | `boolean` | `false` | 当切分页的时候,是否自动跳顶部。 |
| syncResponse2Query | `boolean` | `true` | 将返回数据同步到过滤器上。 |
| keepItemSelectionOnPageChange | `boolean` | `true` | 保留条目选择,默认分页、搜后,用户选择条目会被清空,开启此选项后会保留用户选择,可以实现跨页面批量操作。 |
| keepItemSelectionOnPageChange | `boolean` | `true` | 保留条目选择,默认分页、搜后,用户选择条目会被清空,开启此选项后会保留用户选择,可以实现跨页面批量操作。 |
| labelTpl | `string` | | 单条描述模板,`keepItemSelectionOnPageChange`设置为`true`后会把所有已选择条目列出来,此选项可以用来定制条目展示文案。 |
| maxKeepItemSelectionLength | `number` | `true` | 和`keepItemSelectionOnPageChange`搭配使用,限制最大勾选数。 |
| maxItemSelectionLength | `number` | `true` | 可单独使用限制当前页的最大勾选数,也可以和`keepItemSelectionOnPageChange`搭配使用达到和 maxKeepItemSelectionLength 一样的效果。 |
| headerToolbar | Array | `['bulkActions', 'pagination']` | 顶部工具栏配置 |
| footerToolbar | Array | `['statistics', 'pagination']` | 底部工具栏配置 |
| alwaysShowPagination | `boolean` | `false` | 是否总是显示分页 |

View File

@ -339,13 +339,10 @@ export const Row = types
*/
get isCheckAvaiableOnClick(): boolean {
const table = getParent(self, self.depth * 2) as ITableStore;
const keepItemSelectionOnPageChange =
table?.keepItemSelectionOnPageChange;
const selectionUpperLimit = table?.maxKeepItemSelectionLength;
const selectionUpperLimit = table.getSelectionUpperLimit();
// 如果未做配置,或者配置不合法直接通过检查
if (
!keepItemSelectionOnPageChange ||
!Number.isInteger(selectionUpperLimit) ||
selectionUpperLimit === Infinity
) {
@ -524,6 +521,7 @@ export const TableStore = iRendererStore
formsRef: types.optional(types.array(types.frozen()), []),
maxKeepItemSelectionLength: Infinity,
keepItemSelectionOnPageChange: false,
maxItemSelectionLength: Infinity,
// 导出 Excel 按钮的 loading 状态
exportExcelLoading: false,
searchFormExpanded: false, // 用来控制搜索框是否展开了,那个自动根据 searchable 生成的表单 autoGenerateFilter
@ -776,7 +774,19 @@ export const TableStore = iRendererStore
return self.columns.filter(column => column.searchable);
}
function getSelectionUpperLimit() {
const keep = self.keepItemSelectionOnPageChange;
const selectionUpperLimit = keep
? self.maxKeepItemSelectionLength !== Infinity
? self.maxKeepItemSelectionLength
: self.maxItemSelectionLength
: self.maxItemSelectionLength;
return selectionUpperLimit;
}
return {
getSelectionUpperLimit,
get columnsData() {
return getColumnsExceptBuiltinTypes();
},
@ -819,6 +829,11 @@ export const TableStore = iRendererStore
},
get allChecked(): boolean {
const selectionUpperLimit = getSelectionUpperLimit();
if (selectionUpperLimit !== Infinity) {
return (self as ITableStore).isSelectionThresholdReached;
}
// 只要selectedRows中包含checkableRows中的全部数据就认为是全选
return (self as ITableStore).checkableRows.every(item =>
self.selectedRows.includes(item)
@ -879,9 +894,9 @@ export const TableStore = iRendererStore
/** 已选择item是否达到数量上限 */
get isSelectionThresholdReached() {
const selectedLength = self.data?.selectedItems?.length;
const maxLength = self.maxKeepItemSelectionLength;
const maxLength = getSelectionUpperLimit();
if (!self.data || !self.keepItemSelectionOnPageChange || !maxLength) {
if (!self.data || maxLength === Infinity) {
return false;
}
@ -1073,6 +1088,8 @@ export const TableStore = iRendererStore
config.keepItemSelectionOnPageChange !== undefined &&
(self.keepItemSelectionOnPageChange =
config.keepItemSelectionOnPageChange);
config.maxItemSelectionLength !== undefined &&
(self.maxItemSelectionLength = config.maxItemSelectionLength);
config.exportExcelLoading !== undefined &&
(self.exportExcelLoading = config.exportExcelLoading);
@ -1556,14 +1573,11 @@ export const TableStore = iRendererStore
}
function getSelectedRows() {
const maxLength = self.maxKeepItemSelectionLength;
const keep = self.keepItemSelectionOnPageChange;
const maxLength = self.getSelectionUpperLimit();
const selectedItems = self.data?.selectedItems;
if (
keep &&
maxLength &&
maxLength !== Infinity &&
selectedItems &&
maxLength >= selectedItems.length
) {
@ -1704,11 +1718,11 @@ export const TableStore = iRendererStore
if (!self.data) {
return;
}
const maxLength = self.maxKeepItemSelectionLength;
const maxLength = self.getSelectionUpperLimit();
const selectedItems = self.data.selectedItems;
self.selectedRows.map(item => item.setCheckdisable(false));
if (maxLength && maxLength <= selectedItems.length) {
if (maxLength !== Infinity && maxLength <= selectedItems.length) {
self.unSelectedRows.map(
item => !item.checked && item.setCheckdisable(true)
);

View File

@ -2891,11 +2891,10 @@ exports[`13. enderer: crud keepItemSelectionOnPageChange & maxKeepItemSelectionL
style="left: 0px;"
>
<label
class="cxd-Checkbox cxd-Checkbox--checkbox"
class="cxd-Checkbox cxd-Checkbox--checkbox cxd-Checkbox--full"
data-role="checkbox"
>
<input
disabled=""
type="checkbox"
/>
<i />

View File

@ -2493,6 +2493,7 @@ export default class CRUD extends React.Component<CRUDProps, any> {
classnames: cx,
keepItemSelectionOnPageChange,
maxKeepItemSelectionLength,
maxItemSelectionLength,
onAction,
popOverContainer,
translate: __,
@ -2580,12 +2581,15 @@ export default class CRUD extends React.Component<CRUDProps, any> {
: false
: multiple,
selected:
pickerMode || keepItemSelectionOnPageChange
pickerMode ||
keepItemSelectionOnPageChange ||
maxItemSelectionLength
? store.selectedItemsAsArray
: undefined,
strictMode,
keepItemSelectionOnPageChange,
maxKeepItemSelectionLength,
maxItemSelectionLength,
valueField: valueField || primaryField,
primaryField: primaryField,
hideQuickSaveBtn,

View File

@ -376,6 +376,7 @@ export interface TableProps extends RendererProps, SpinnerExtraProps {
selectable?: boolean;
selected?: Array<any>;
maxKeepItemSelectionLength?: number;
maxItemSelectionLength?: number;
valueField?: string;
draggable?: boolean;
columnsTogglable?: boolean | 'auto';
@ -508,6 +509,7 @@ export default class Table extends React.Component<TableProps, object> {
'onSelect',
'keepItemSelectionOnPageChange',
'maxKeepItemSelectionLength',
'maxItemSelectionLength',
'autoGenerateFilter'
];
static defaultProps: Partial<TableProps> = {
@ -605,6 +607,7 @@ export default class Table extends React.Component<TableProps, object> {
formItem,
keepItemSelectionOnPageChange,
maxKeepItemSelectionLength,
maxItemSelectionLength,
onQuery,
autoGenerateFilter,
loading,
@ -641,6 +644,7 @@ export default class Table extends React.Component<TableProps, object> {
combineFromIndex,
keepItemSelectionOnPageChange,
maxKeepItemSelectionLength,
maxItemSelectionLength,
loading,
canAccessSuperData,
lazyRenderAfter,
@ -1838,7 +1842,7 @@ export default class Table extends React.Component<TableProps, object> {
classPrefix={ns}
partial={store.someChecked && !store.allChecked}
checked={store.someChecked}
disabled={store.isSelectionThresholdReached}
disabled={store.isSelectionThresholdReached && !store.someChecked}
onChange={this.handleCheckAll}
/>
) : (