Skip to content

Commit

Permalink
feat: inputTable 支持前端过滤与排序并优化新增节点不可见的问题 (#11208)
Browse files Browse the repository at this point in the history
* feat: inputTable 新增选项时自动跳转到对应的分页

* feat: inputTable 支持前端过滤与排序并优化新增节点不可见的问题
  • Loading branch information
2betop authored Nov 18, 2024
1 parent 539074e commit 4e4f06c
Show file tree
Hide file tree
Showing 5 changed files with 401 additions and 228 deletions.
99 changes: 96 additions & 3 deletions docs/zh-CN/components/form/input-table.md
Original file line number Diff line number Diff line change
Expand Up @@ -478,19 +478,112 @@ order: 54
},
"body": [
{
"showIndex": true,
"type":"input-table",
"perPage": 5,
"name":"table",
"addable": true,
"showIndex": true,
"columns":[
{
"name": "a",
"label": "A"
"label": "A",
"searchable": true
},
{
"name": "b",
"label": "B"
"label": "B",
"sortable": true
}
]
}
]
}
```

## 前端过滤与排序

> 6.10.0 及以上版本
在列上配置 `searchable``sortable` 或者 `filterable` 来开启对应功能,用法与 [CRUD](../crud#快速搜索) 一致。

```schema: scope="body"
{
"type": "form",
"initApi": "/api/mock2/sample",
"body": [
{
"type":"input-table",
"perPage": 10,
"name":"rows",
"addable": true,
"copyable": true,
"editable": true,
"removable": true,
"showIndex": true,
"columns":[
{
"name": "grade",
"label": "CSS grade",
"filterable": {
"options": [
"A",
"B",
"C",
"D",
"X"
]
}
},
{
"name": "version",
"label": "Version",
"searchable": true
}
]
}
]
}
```

默认前端只是简单的过滤,如果要有复杂过滤,请通过 `matchFunc` 来实现,函数签名 `(items: Record<string, any>[], itemsRaw: Record<string, any>[], options: {query: string, columns: Column[], matchSorter: (a: any, b: any) => number}) => Record<string, any>[]`

- `items` 当前表格数据
- `itemsRaw` 与 items 一样,(历史用法,保持不变)
- `options` 配置
- `options.query` 查询条件
- `options.columns` 列配置
- `options.matchSorter` 系统默认的排序方法

```schema: scope="body"
{
"type": "form",
"initApi": "/api/mock2/sample",
"body": [
{
"type":"input-table",
"perPage": 10,
"name":"rows",
"addable": true,
"matchFunc": "const query = options.query;if (query.version === '>=20') {items = items.filter(item => parseFloat(item.version) >= 20);} else if (query.version ==='<20') {items = items.filter(item => parseFloat(item.version) < 20);}return items;",
"columns":[
{
"name": "id",
"label": "ID"
},
{
"name": "grade",
"label": "CSS grade"
},
{
"name": "version",
"label": "Version",
"filterable": {
"options": [
">=20",
"<20"
]
}
}
]
}
]
Expand Down
51 changes: 6 additions & 45 deletions packages/amis-core/src/store/crud.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
createObject,
isObjectShallowModified,
sortArray,
applyFilters,
isEmpty,
qsstringify,
getVariable
Expand Down Expand Up @@ -237,51 +238,11 @@ export const CRUDStore = ServiceStore.named('CRUDStore')
)
: self.items.concat();

/** 字段的格式类型无法穷举,所以支持使用函数过滤 */
if (matchFunc && typeof matchFunc === 'function') {
items = matchFunc(items, self.data.itemsRaw, {
query: self.query,
columns: options.columns,
matchSorter: matchSorter
});
} else {
if (Array.isArray(options.columns)) {
options.columns.forEach((column: any) => {
let value: any =
typeof column.name === 'string'
? getVariable(self.query, column.name)
: undefined;
const key = column.name;

if (value != null && key) {
// value可能为null、undefined、''、0
if (Array.isArray(value)) {
if (value.length > 0) {
const arr = [...items];
let arrItems: Array<any> = [];
value.forEach(item => {
arrItems = [
...arrItems,
...matchSorter(arr, item, {
keys: [key],
threshold: matchSorter.rankings.CONTAINS
})
];
});
items = items.filter((item: any) =>
arrItems.find(a => a === item)
);
}
} else {
items = matchSorter(items, value, {
keys: [key],
threshold: matchSorter.rankings.CONTAINS
});
}
}
});
}
}
items = applyFilters(items, {
query: self.query,
columns: options.columns,
matchFunc: matchFunc
});

if (self.query.orderBy) {
const dir = /desc/i.test(self.query.orderDir) ? -1 : 1;
Expand Down
52 changes: 52 additions & 0 deletions packages/amis-core/src/utils/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import isNumber from 'lodash/isNumber';
import isString from 'lodash/isString';
import qs from 'qs';
import {compile} from 'path-to-regexp';
import {matchSorter} from 'match-sorter';

import type {Schema, PlainObject, FunctionPropertyNames} from '../types';

Expand Down Expand Up @@ -1497,6 +1498,57 @@ export function sortArray<T extends any>(
});
}

export function applyFilters<T extends any>(
items: Array<T>,
options: {
query: any;
columns?: Array<any>;
matchFunc?: Function;
}
) {
if (options.matchFunc && typeof options.matchFunc === 'function') {
items = options.matchFunc(items, items, options);
} else {
if (Array.isArray(options.columns)) {
options.columns.forEach((column: any) => {
let value: any =
typeof column.name === 'string'
? getVariable(options.query, column.name)
: undefined;
const key = column.name;

if (value != null && key) {
// value可能为null、undefined、''、0
if (Array.isArray(value)) {
if (value.length > 0) {
const arr = [...items];
let arrItems: Array<any> = [];
value.forEach(item => {
arrItems = [
...arrItems,
...matchSorter(arr, item, {
keys: [key],
threshold: matchSorter.rankings.CONTAINS
})
];
});
items = items.filter((item: any) =>
arrItems.find(a => a === item)
);
}
} else {
items = matchSorter(items, value, {
keys: [key],
threshold: matchSorter.rankings.CONTAINS
});
}
}
});
}
} /** 字段的格式类型无法穷举,所以支持使用函数过滤 */
return items;
}

// 只判断一层, 如果层级很深,form-data 也不好表达。
export function hasFile(object: any): boolean {
return Object.keys(object).some(key => {
Expand Down
9 changes: 9 additions & 0 deletions packages/amis/src/renderers/CRUD.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,15 @@ export interface CRUDCommonSchema extends BaseSchema, SpinnerExtraProps {

/**
* 自定义搜索匹配函数,当开启loadDataOnce时,会基于该函数计算的匹配结果进行过滤,主要用于处理列字段类型较为复杂或者字段值格式和后端返回不一致的场景
*
* 参数说明
*
* * `items` 当前表格数据
* * `itemsRaw` 当前表格数据(未处理)
* * `options` 配置
* * `options.query` 查询条件
* * `options.columns` 列配置
* * `options.matchSorter` 系统默认的排序方法
* @since 3.5.0
*/
matchFunc?: string | any;
Expand Down
Loading

0 comments on commit 4e4f06c

Please sign in to comment.