mirror of
https://gitee.com/baidu/amis.git
synced 2024-12-02 03:58:07 +08:00
parent
b0f12d7557
commit
cd5cd3f40c
@ -200,11 +200,11 @@ CRUD 组件对数据源接口的数据结构要求如下:
|
|||||||
| orderDir | 'asc'/'desc' | 排序方式 |
|
| orderDir | 'asc'/'desc' | 排序方式 |
|
||||||
| keywords | string | 搜索关键字 |
|
| keywords | string | 搜索关键字 |
|
||||||
|
|
||||||
### 解析Query原始类型
|
### 解析 Query 原始类型
|
||||||
|
|
||||||
> `3.5.0`及以上版本
|
> `3.5.0`及以上版本
|
||||||
|
|
||||||
`syncLocation`开启后,CRUD在初始化数据域时,将会对url中的Query进行转换,将原始类型的字符串格式的转化为同位类型,目前仅支持**布尔类型**
|
`syncLocation`开启后,CRUD 在初始化数据域时,将会对 url 中的 Query 进行转换,将原始类型的字符串格式的转化为同位类型,目前仅支持**布尔类型**
|
||||||
|
|
||||||
```
|
```
|
||||||
"true" ==> true
|
"true" ==> true
|
||||||
@ -213,7 +213,6 @@ CRUD 组件对数据源接口的数据结构要求如下:
|
|||||||
|
|
||||||
如果只想保持字符串格式,可以设置`"parsePrimitiveQuery": false`关闭该特性,具体效果参考[示例](../../../examples/crud/parse-primitive-query)。
|
如果只想保持字符串格式,可以设置`"parsePrimitiveQuery": false`关闭该特性,具体效果参考[示例](../../../examples/crud/parse-primitive-query)。
|
||||||
|
|
||||||
|
|
||||||
## 功能
|
## 功能
|
||||||
|
|
||||||
既然这个渲染器叫增删改查,那接下来分开介绍这几个功能吧。
|
既然这个渲染器叫增删改查,那接下来分开介绍这几个功能吧。
|
||||||
@ -584,6 +583,61 @@ Cards 模式支持 [Cards](./cards) 中的所有功能。
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 嵌套
|
||||||
|
|
||||||
|
当行数据中存在 `children` 字段时,CRUD 会自动识别为树形数据,并支持展开收起。
|
||||||
|
|
||||||
|
```schema: scope="body"
|
||||||
|
{
|
||||||
|
"type": "crud",
|
||||||
|
"name": "crud",
|
||||||
|
"syncLocation": false,
|
||||||
|
"api": "/api/mock2/crud/table2",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"label": "ID"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "engine",
|
||||||
|
"label": "Rendering engine"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "browser",
|
||||||
|
"label": "Browser"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 嵌套懒加载
|
||||||
|
|
||||||
|
如果数据量比较大不适合一次性加载,可以配置 `deferApi` 接口,结合行数据中标记 `defer: true` 属性,实现懒加载。
|
||||||
|
|
||||||
|
```schema: scope="body"
|
||||||
|
{
|
||||||
|
"type": "crud",
|
||||||
|
"name": "crud",
|
||||||
|
"syncLocation": false,
|
||||||
|
"api": "/api/mock2/crud/table6",
|
||||||
|
"deferApi": "/api/mock2/crud/table6?parentId=${id}",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"label": "ID"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "engine",
|
||||||
|
"label": "Rendering engine"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "browser",
|
||||||
|
"label": "Browser"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## 查询条件表单
|
## 查询条件表单
|
||||||
|
|
||||||
大部分表格展示有对数据进行检索的需求,CRUD 自身支持通过配置`filter`,实现查询条件过滤表单。`filter` 配置实际上同 [Form](./form/index) 组件,因此支持绝大部分`form`的功能。
|
大部分表格展示有对数据进行检索的需求,CRUD 自身支持通过配置`filter`,实现查询条件过滤表单。`filter` 配置实际上同 [Form](./form/index) 组件,因此支持绝大部分`form`的功能。
|
||||||
@ -3173,6 +3227,7 @@ itemAction 里的 onClick 还能通过 `data` 参数拿到当前行的数据,
|
|||||||
| title | `string` | `""` | 可设置成空,当设置成空时,没有标题栏 |
|
| title | `string` | `""` | 可设置成空,当设置成空时,没有标题栏 |
|
||||||
| className | `string` | | 表格外层 Dom 的类名 |
|
| className | `string` | | 表格外层 Dom 的类名 |
|
||||||
| api | [API](../../docs/types/api) | | CRUD 用来获取列表数据的 api。 |
|
| api | [API](../../docs/types/api) | | CRUD 用来获取列表数据的 api。 |
|
||||||
|
| deferApi | [API](../../docs/types/api) | | 当行数据中有 defer 属性时,用此接口进一步加载内容 |
|
||||||
| loadDataOnce | `boolean` | | 是否一次性加载所有数据(前端分页) |
|
| loadDataOnce | `boolean` | | 是否一次性加载所有数据(前端分页) |
|
||||||
| loadDataOnceFetchOnFilter | `boolean` | `true` | 在开启 loadDataOnce 时,filter 时是否去重新请求 api |
|
| loadDataOnceFetchOnFilter | `boolean` | `true` | 在开启 loadDataOnce 时,filter 时是否去重新请求 api |
|
||||||
| source | `string` | | 数据映射接口返回某字段的值,不设置会默认使用接口返回的`${items}`或者`${rows}`,也可以设置成上层数据源的内容 |
|
| source | `string` | | 数据映射接口返回某字段的值,不设置会默认使用接口返回的`${items}`或者`${rows}`,也可以设置成上层数据源的内容 |
|
||||||
|
@ -1825,6 +1825,7 @@ popOver 的其它配置请参考 [popover](./popover)
|
|||||||
| type | `string` | | `"type"` 指定为 table 渲染器 | |
|
| type | `string` | | `"type"` 指定为 table 渲染器 | |
|
||||||
| title | `string` | | 标题 | |
|
| title | `string` | | 标题 | |
|
||||||
| source | `string` | `${items}` | 数据源, 绑定当前环境变量 | |
|
| source | `string` | `${items}` | 数据源, 绑定当前环境变量 | |
|
||||||
|
| deferApi | [API](../../docs/types/api) | | 当行数据中有 defer 属性时,用此接口进一步加载内容 |
|
||||||
| affixHeader | `boolean` | `true` | 是否固定表头 | |
|
| affixHeader | `boolean` | `true` | 是否固定表头 | |
|
||||||
| columnsTogglable | `auto` 或者 `boolean` | `auto` | 展示列显示开关, 自动即:列数量大于或等于 5 个时自动开启 | |
|
| columnsTogglable | `auto` 或者 `boolean` | `auto` | 展示列显示开关, 自动即:列数量大于或等于 5 个时自动开启 | |
|
||||||
| placeholder | `string` 或者 `SchemaTpl` | `暂无数据` | 当没数据的时候的文字提示 | |
|
| placeholder | `string` 或者 `SchemaTpl` | `暂无数据` | 当没数据的时候的文字提示 | |
|
||||||
|
@ -2,11 +2,9 @@ export default {
|
|||||||
title: '支持多层嵌套,列数据中有 children 字段即可。(建议不超过10层)',
|
title: '支持多层嵌套,列数据中有 children 字段即可。(建议不超过10层)',
|
||||||
body: {
|
body: {
|
||||||
type: 'crud',
|
type: 'crud',
|
||||||
api: '/api/mock2/crud/table2',
|
api: '/api/mock2/crud/table6',
|
||||||
|
deferApi: '/api/mock2/crud/table6?parentId=${id}',
|
||||||
saveOrderApi: '/api/mock2/form/saveData',
|
saveOrderApi: '/api/mock2/form/saveData',
|
||||||
expandConfig: {
|
|
||||||
expand: 'all'
|
|
||||||
},
|
|
||||||
draggable: true,
|
draggable: true,
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
|
527
mock/cfc/mock/crud/table6.js
Normal file
527
mock/cfc/mock/crud/table6.js
Normal file
@ -0,0 +1,527 @@
|
|||||||
|
function findInTree(tree, id) {
|
||||||
|
let ret = null;
|
||||||
|
tree.some(function (item) {
|
||||||
|
if (item.id == id) {
|
||||||
|
ret = item;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (item.children) {
|
||||||
|
ret = findInTree(item.children, id);
|
||||||
|
return !!ret;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function (req, res) {
|
||||||
|
const perPage = 10;
|
||||||
|
const page = req.query.page || 1;
|
||||||
|
let items = data.concat();
|
||||||
|
if (req.query.parentId) {
|
||||||
|
const item = findInTree(items, req.query.parentId);
|
||||||
|
|
||||||
|
if (!item) {
|
||||||
|
res.json({
|
||||||
|
status: 404,
|
||||||
|
msg: 'Not Found'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
status: 0,
|
||||||
|
msg: 'ok',
|
||||||
|
data: {
|
||||||
|
...item,
|
||||||
|
children: Array.isArray(item.children)
|
||||||
|
? item.children.map(item => ({
|
||||||
|
...item,
|
||||||
|
children: undefined,
|
||||||
|
defer: !!(Array.isArray(item.children) && item.children.length)
|
||||||
|
}))
|
||||||
|
: []
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const ret = {
|
||||||
|
status: 0,
|
||||||
|
msg: 'ok',
|
||||||
|
data: {
|
||||||
|
count: items.length,
|
||||||
|
rows: items
|
||||||
|
.concat()
|
||||||
|
.splice((page - 1) * perPage, perPage)
|
||||||
|
.map(item => ({
|
||||||
|
...item,
|
||||||
|
children: undefined,
|
||||||
|
defer: !!(Array.isArray(item.children) && item.children.length)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
res.json(ret);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.cache = true;
|
||||||
|
const data = [
|
||||||
|
{
|
||||||
|
engine: 'Trident',
|
||||||
|
browser: 'Internet Explorer 4.0',
|
||||||
|
platform: 'Win 95+',
|
||||||
|
version: '4',
|
||||||
|
grade: 'X'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Trident',
|
||||||
|
browser: 'Internet Explorer 5.0',
|
||||||
|
platform: 'Win 95+',
|
||||||
|
version: '5',
|
||||||
|
grade: 'C'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Trident',
|
||||||
|
browser: 'Internet Explorer 5.5',
|
||||||
|
platform: 'Win 95+',
|
||||||
|
version: '5.5',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Trident',
|
||||||
|
browser: 'Internet Explorer 6',
|
||||||
|
platform: 'Win 98+',
|
||||||
|
version: '6',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Trident',
|
||||||
|
browser: 'Internet Explorer 7',
|
||||||
|
platform: 'Win XP SP2+',
|
||||||
|
version: '7',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Trident',
|
||||||
|
browser: 'AOL browser (AOL desktop)',
|
||||||
|
platform: 'Win XP',
|
||||||
|
version: '6',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Gecko',
|
||||||
|
browser: 'Firefox 1.0',
|
||||||
|
platform: 'Win 98+ / OSX.2+',
|
||||||
|
version: '1.7',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Gecko',
|
||||||
|
browser: 'Firefox 1.5',
|
||||||
|
platform: 'Win 98+ / OSX.2+',
|
||||||
|
version: '1.8',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Gecko',
|
||||||
|
browser: 'Firefox 2.0',
|
||||||
|
platform: 'Win 98+ / OSX.2+',
|
||||||
|
version: '1.8',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Gecko',
|
||||||
|
browser: 'Firefox 3.0',
|
||||||
|
platform: 'Win 2k+ / OSX.3+',
|
||||||
|
version: '1.9',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Gecko',
|
||||||
|
browser: 'Camino 1.0',
|
||||||
|
platform: 'OSX.2+',
|
||||||
|
version: '1.8',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Gecko',
|
||||||
|
browser: 'Camino 1.5',
|
||||||
|
platform: 'OSX.3+',
|
||||||
|
version: '1.8',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Gecko',
|
||||||
|
browser: 'Netscape 7.2',
|
||||||
|
platform: 'Win 95+ / Mac OS 8.6-9.2',
|
||||||
|
version: '1.7',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Gecko',
|
||||||
|
browser: 'Netscape Browser 8',
|
||||||
|
platform: 'Win 98SE+',
|
||||||
|
version: '1.7',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Gecko',
|
||||||
|
browser: 'Netscape Navigator 9',
|
||||||
|
platform: 'Win 98+ / OSX.2+',
|
||||||
|
version: '1.8',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Gecko',
|
||||||
|
browser: 'Mozilla 1.0',
|
||||||
|
platform: 'Win 95+ / OSX.1+',
|
||||||
|
version: '1',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Gecko',
|
||||||
|
browser: 'Mozilla 1.1',
|
||||||
|
platform: 'Win 95+ / OSX.1+',
|
||||||
|
version: '1.1',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Gecko',
|
||||||
|
browser: 'Mozilla 1.2',
|
||||||
|
platform: 'Win 95+ / OSX.1+',
|
||||||
|
version: '1.2',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Gecko',
|
||||||
|
browser: 'Mozilla 1.3',
|
||||||
|
platform: 'Win 95+ / OSX.1+',
|
||||||
|
version: '1.3',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Gecko',
|
||||||
|
browser: 'Mozilla 1.4',
|
||||||
|
platform: 'Win 95+ / OSX.1+',
|
||||||
|
version: '1.4',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Gecko',
|
||||||
|
browser: 'Mozilla 1.5',
|
||||||
|
platform: 'Win 95+ / OSX.1+',
|
||||||
|
version: '1.5',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Gecko',
|
||||||
|
browser: 'Mozilla 1.6',
|
||||||
|
platform: 'Win 95+ / OSX.1+',
|
||||||
|
version: '1.6',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Gecko',
|
||||||
|
browser: 'Mozilla 1.7',
|
||||||
|
platform: 'Win 98+ / OSX.1+',
|
||||||
|
version: '1.7',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Gecko',
|
||||||
|
browser: 'Mozilla 1.8',
|
||||||
|
platform: 'Win 98+ / OSX.1+',
|
||||||
|
version: '1.8',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Gecko',
|
||||||
|
browser: 'Seamonkey 1.1',
|
||||||
|
platform: 'Win 98+ / OSX.2+',
|
||||||
|
version: '1.8',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Gecko',
|
||||||
|
browser: 'Epiphany 2.20',
|
||||||
|
platform: 'Gnome',
|
||||||
|
version: '1.8',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Webkit',
|
||||||
|
browser: 'Safari 1.2',
|
||||||
|
platform: 'OSX.3',
|
||||||
|
version: '125.5',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Webkit',
|
||||||
|
browser: 'Safari 1.3',
|
||||||
|
platform: 'OSX.3',
|
||||||
|
version: '312.8',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Webkit',
|
||||||
|
browser: 'Safari 2.0',
|
||||||
|
platform: 'OSX.4+',
|
||||||
|
version: '419.3',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Webkit',
|
||||||
|
browser: 'Safari 3.0',
|
||||||
|
platform: 'OSX.4+',
|
||||||
|
version: '522.1',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Webkit',
|
||||||
|
browser: 'OmniWeb 5.5',
|
||||||
|
platform: 'OSX.4+',
|
||||||
|
version: '420',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Webkit',
|
||||||
|
browser: 'iPod Touch / iPhone',
|
||||||
|
platform: 'iPod',
|
||||||
|
version: '420.1',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Webkit',
|
||||||
|
browser: 'S60',
|
||||||
|
platform: 'S60',
|
||||||
|
version: '413',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Presto',
|
||||||
|
browser: 'Opera 7.0',
|
||||||
|
platform: 'Win 95+ / OSX.1+',
|
||||||
|
version: '-',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Presto',
|
||||||
|
browser: 'Opera 7.5',
|
||||||
|
platform: 'Win 95+ / OSX.2+',
|
||||||
|
version: '-',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Presto',
|
||||||
|
browser: 'Opera 8.0',
|
||||||
|
platform: 'Win 95+ / OSX.2+',
|
||||||
|
version: '-',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Presto',
|
||||||
|
browser: 'Opera 8.5',
|
||||||
|
platform: 'Win 95+ / OSX.2+',
|
||||||
|
version: '-',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Presto',
|
||||||
|
browser: 'Opera 9.0',
|
||||||
|
platform: 'Win 95+ / OSX.3+',
|
||||||
|
version: '-',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Presto',
|
||||||
|
browser: 'Opera 9.2',
|
||||||
|
platform: 'Win 88+ / OSX.3+',
|
||||||
|
version: '-',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Presto',
|
||||||
|
browser: 'Opera 9.5',
|
||||||
|
platform: 'Win 88+ / OSX.3+',
|
||||||
|
version: '-',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Presto',
|
||||||
|
browser: 'Opera for Wii',
|
||||||
|
platform: 'Wii',
|
||||||
|
version: '-',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Presto',
|
||||||
|
browser: 'Nokia N800',
|
||||||
|
platform: 'N800',
|
||||||
|
version: '-',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Presto',
|
||||||
|
browser: 'Nintendo DS browser',
|
||||||
|
platform: 'Nintendo DS',
|
||||||
|
version: '8.5',
|
||||||
|
grade: 'C'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'KHTML',
|
||||||
|
browser: 'Konqureror 3.1',
|
||||||
|
platform: 'KDE 3.1',
|
||||||
|
version: '3.1',
|
||||||
|
grade: 'C'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'KHTML',
|
||||||
|
browser: 'Konqureror 3.3',
|
||||||
|
platform: 'KDE 3.3',
|
||||||
|
version: '3.3',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'KHTML',
|
||||||
|
browser: 'Konqureror 3.5',
|
||||||
|
platform: 'KDE 3.5',
|
||||||
|
version: '3.5',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Tasman',
|
||||||
|
browser: 'Internet Explorer 4.5',
|
||||||
|
platform: 'Mac OS 8-9',
|
||||||
|
version: '-',
|
||||||
|
grade: 'X'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Tasman',
|
||||||
|
browser: 'Internet Explorer 5.1',
|
||||||
|
platform: 'Mac OS 7.6-9',
|
||||||
|
version: '1',
|
||||||
|
grade: 'C'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Tasman',
|
||||||
|
browser: 'Internet Explorer 5.2',
|
||||||
|
platform: 'Mac OS 8-X',
|
||||||
|
version: '1',
|
||||||
|
grade: 'C'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Misc',
|
||||||
|
browser: 'NetFront 3.1',
|
||||||
|
platform: 'Embedded devices',
|
||||||
|
version: '-',
|
||||||
|
grade: 'C'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Misc',
|
||||||
|
browser: 'NetFront 3.4',
|
||||||
|
platform: 'Embedded devices',
|
||||||
|
version: '-',
|
||||||
|
grade: 'A'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Misc',
|
||||||
|
browser: 'Dillo 0.8',
|
||||||
|
platform: 'Embedded devices',
|
||||||
|
version: '-',
|
||||||
|
grade: 'X'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Misc',
|
||||||
|
browser: 'Links',
|
||||||
|
platform: 'Text only',
|
||||||
|
version: '-',
|
||||||
|
grade: 'X'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Misc',
|
||||||
|
browser: 'Lynx',
|
||||||
|
platform: 'Text only',
|
||||||
|
version: '-',
|
||||||
|
grade: 'X'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Misc',
|
||||||
|
browser: 'IE Mobile',
|
||||||
|
platform: 'Windows Mobile 6',
|
||||||
|
version: '-',
|
||||||
|
grade: 'C'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Misc',
|
||||||
|
browser: 'PSP browser',
|
||||||
|
platform: 'PSP',
|
||||||
|
version: '-',
|
||||||
|
grade: 'C'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Other browsers',
|
||||||
|
browser: 'All others',
|
||||||
|
platform: '-',
|
||||||
|
version: '-',
|
||||||
|
grade: 'U'
|
||||||
|
}
|
||||||
|
].map(function (item, index) {
|
||||||
|
return Object.assign({}, item, {
|
||||||
|
id: index + 1,
|
||||||
|
children:
|
||||||
|
Math.random() > 0.5
|
||||||
|
? undefined
|
||||||
|
: [
|
||||||
|
{
|
||||||
|
engine: 'Trident',
|
||||||
|
browser: 'Internet Explorer 4.0',
|
||||||
|
platform: 'Win 95+',
|
||||||
|
version: '4',
|
||||||
|
grade: 'X'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Trident',
|
||||||
|
browser: 'Internet Explorer 5.0',
|
||||||
|
platform: 'Win 95+',
|
||||||
|
version: '5',
|
||||||
|
grade: 'C'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Other browsers',
|
||||||
|
browser: 'All others',
|
||||||
|
platform: '-',
|
||||||
|
version: '-',
|
||||||
|
grade: 'U'
|
||||||
|
}
|
||||||
|
].map(function (child, i) {
|
||||||
|
return Object.assign({}, child, {
|
||||||
|
id: (index + 1) * 100 + i + 1,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
engine: 'Trident',
|
||||||
|
browser: 'Internet Explorer 4.0',
|
||||||
|
platform: 'Win 95+',
|
||||||
|
version: '4',
|
||||||
|
grade: 'X'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Misc',
|
||||||
|
browser: 'Internet Explorer 5.0',
|
||||||
|
platform: 'Win 95+',
|
||||||
|
version: '5',
|
||||||
|
grade: 'C'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
engine: 'Misc',
|
||||||
|
browser: 'Internet Explorer 5.0',
|
||||||
|
platform: 'Win 95+',
|
||||||
|
version: '1',
|
||||||
|
grade: 'A'
|
||||||
|
}
|
||||||
|
].map(function (child, i) {
|
||||||
|
return Object.assign({}, child, {
|
||||||
|
id: (i + 1) * 100 + (index + 1) * 1000 + i + 1
|
||||||
|
});
|
||||||
|
})
|
||||||
|
});
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
@ -27,15 +27,20 @@ module.exports = function (req, res) {
|
|||||||
return require(file)(req, res);
|
return require(file)(req, res);
|
||||||
} else if (exist(jsFile)) {
|
} else if (exist(jsFile)) {
|
||||||
let file = require.resolve(path.join(DIRNAME, jsFile));
|
let file = require.resolve(path.join(DIRNAME, jsFile));
|
||||||
delete require.cache[file];
|
let mod = require(file);
|
||||||
|
|
||||||
|
if (!mod.cache) {
|
||||||
|
delete require.cache[file];
|
||||||
|
mod = require(file);
|
||||||
|
}
|
||||||
|
|
||||||
if (req.query.waitSeconds) {
|
if (req.query.waitSeconds) {
|
||||||
return setTimeout(function () {
|
return setTimeout(function () {
|
||||||
require(file)(req, res);
|
mod(req, res);
|
||||||
}, parseInt(req.query.waitSeconds, 10) * 1000);
|
}, parseInt(req.query.waitSeconds, 10) * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
return require(file)(req, res);
|
return mod(req, res);
|
||||||
}
|
}
|
||||||
if (exist(jsonFile)) {
|
if (exist(jsonFile)) {
|
||||||
if (req.query.waitSeconds) {
|
if (req.query.waitSeconds) {
|
||||||
|
@ -39,6 +39,45 @@ import {getStoreById} from './manager';
|
|||||||
*/
|
*/
|
||||||
const PARTITION_INDEX = 3;
|
const PARTITION_INDEX = 3;
|
||||||
|
|
||||||
|
function initChildren(
|
||||||
|
children: Array<any>,
|
||||||
|
depth: number,
|
||||||
|
pindex: number,
|
||||||
|
parentId: string,
|
||||||
|
path: string = ''
|
||||||
|
): any {
|
||||||
|
depth += 1;
|
||||||
|
return children.map((item, index) => {
|
||||||
|
item = isObject(item)
|
||||||
|
? item
|
||||||
|
: {
|
||||||
|
item
|
||||||
|
};
|
||||||
|
const id = item.__id ?? guid();
|
||||||
|
|
||||||
|
return {
|
||||||
|
// id: String(item && (item as any)[self.primaryField] || `${pindex}-${depth}-${key}`),
|
||||||
|
id: String(id),
|
||||||
|
parentId: String(parentId),
|
||||||
|
key: String(`${pindex}-${depth}-${index}`),
|
||||||
|
path: `${path}${index}`,
|
||||||
|
depth: depth,
|
||||||
|
index: index,
|
||||||
|
newIndex: index,
|
||||||
|
pristine: item,
|
||||||
|
data: item,
|
||||||
|
defer: !!item.defer,
|
||||||
|
loaded: false,
|
||||||
|
loading: false,
|
||||||
|
rowSpans: {},
|
||||||
|
children:
|
||||||
|
item && Array.isArray(item.children)
|
||||||
|
? initChildren(item.children, depth, index, id, `${path}${index}.`)
|
||||||
|
: []
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export const Column = types
|
export const Column = types
|
||||||
.model('Column', {
|
.model('Column', {
|
||||||
label: types.optional(types.frozen(), undefined),
|
label: types.optional(types.frozen(), undefined),
|
||||||
@ -127,20 +166,33 @@ export const Row = types
|
|||||||
rowSpans: types.frozen({} as any),
|
rowSpans: types.frozen({} as any),
|
||||||
index: types.number,
|
index: types.number,
|
||||||
newIndex: types.number,
|
newIndex: types.number,
|
||||||
nth: 0,
|
|
||||||
path: '', // 行数据的位置
|
path: '', // 行数据的位置
|
||||||
expandable: false,
|
|
||||||
checkdisable: false,
|
checkdisable: false,
|
||||||
isHover: false,
|
isHover: false,
|
||||||
children: types.optional(
|
children: types.optional(
|
||||||
types.array(types.late((): IAnyModelType => Row)),
|
types.array(types.late((): IAnyModelType => Row)),
|
||||||
[]
|
[]
|
||||||
),
|
),
|
||||||
|
defer: false, // 是否为懒数据
|
||||||
|
loaded: false, // 懒数据是否加载完了
|
||||||
|
loading: false, // 懒数据是否正在加载
|
||||||
|
error: '', // 懒数据加载失败的错误信息
|
||||||
depth: types.number, // 当前children位于第几层,便于使用getParent获取最顶层TableStore
|
depth: types.number, // 当前children位于第几层,便于使用getParent获取最顶层TableStore
|
||||||
appeared: true,
|
appeared: true,
|
||||||
lazyRender: false
|
lazyRender: false
|
||||||
})
|
})
|
||||||
.views(self => ({
|
.views(self => ({
|
||||||
|
get expandable(): boolean {
|
||||||
|
let table: any;
|
||||||
|
return !!(
|
||||||
|
(self && self.children.length) ||
|
||||||
|
(self && self.defer && !self.loaded) ||
|
||||||
|
((table = getParent(self, self.depth * 2) as any) &&
|
||||||
|
table.footable &&
|
||||||
|
table.footableColumns.length)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
get checked(): boolean {
|
get checked(): boolean {
|
||||||
return (getParent(self, self.depth * 2) as ITableStore).isSelected(
|
return (getParent(self, self.depth * 2) as ITableStore).isSelected(
|
||||||
self as IRow
|
self as IRow
|
||||||
@ -320,36 +372,70 @@ export const Row = types
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (Array.isArray(data.children)) {
|
if (Array.isArray(data.children)) {
|
||||||
const arr = data.children;
|
this.replaceChildren(data.children);
|
||||||
const pool = arr.concat();
|
}
|
||||||
|
},
|
||||||
|
|
||||||
// 把多的删了先
|
replaceChildren(children: Array<any>) {
|
||||||
if (self.children.length > arr.length) {
|
const arr = children;
|
||||||
self.children.splice(arr.length, self.children.length - arr.length);
|
const pool = arr.concat();
|
||||||
}
|
|
||||||
|
// 把多的删了先
|
||||||
let index = 0;
|
if (self.children.length > arr.length) {
|
||||||
const len = self.children.length;
|
self.children.splice(arr.length, self.children.length - arr.length);
|
||||||
while (pool.length) {
|
}
|
||||||
// 因为父级id未更新,所以需要将子级的parentId正确指向父级id
|
|
||||||
const item = {
|
let index = 0;
|
||||||
...pool.shift(),
|
const len = self.children.length;
|
||||||
parentId: self.id
|
while (pool.length) {
|
||||||
}!;
|
// 因为父级id未更新,所以需要将子级的parentId正确指向父级id
|
||||||
|
const item = {
|
||||||
if (index < len) {
|
...pool.shift(),
|
||||||
self.children[index].replaceWith(item);
|
parentId: self.id
|
||||||
} else {
|
}!;
|
||||||
const row = Row.create(item);
|
|
||||||
self.children.push(row);
|
if (index < len) {
|
||||||
}
|
self.children[index].replaceWith(item);
|
||||||
index++;
|
} else {
|
||||||
|
const row = Row.create(item);
|
||||||
|
self.children.push(row);
|
||||||
}
|
}
|
||||||
|
index++;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
markAppeared(value: any) {
|
markAppeared(value: any) {
|
||||||
value && (self.appeared = !!value);
|
value && (self.appeared = !!value);
|
||||||
|
},
|
||||||
|
|
||||||
|
markLoading(value: any) {
|
||||||
|
self.loading = !!value;
|
||||||
|
},
|
||||||
|
|
||||||
|
markLoaded(value: any) {
|
||||||
|
self.loaded = !!value;
|
||||||
|
},
|
||||||
|
|
||||||
|
setError(value: any) {
|
||||||
|
self.error = String(value);
|
||||||
|
},
|
||||||
|
|
||||||
|
resetDefered() {
|
||||||
|
self.error = '';
|
||||||
|
self.loaded = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
setDeferData({children, ...rest}: any) {
|
||||||
|
self.data = {
|
||||||
|
...self.data,
|
||||||
|
...rest
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Array.isArray(children)) {
|
||||||
|
this.replaceChildren(
|
||||||
|
initChildren(children, self.depth, self.index, self.id, self.path)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -1238,55 +1324,6 @@ export const TableStore = iRendererStore
|
|||||||
return combineCell(arr, keys);
|
return combineCell(arr, keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
function initChildren(
|
|
||||||
children: Array<any>,
|
|
||||||
depth: number,
|
|
||||||
pindex: number,
|
|
||||||
parentId: string,
|
|
||||||
path: string = '',
|
|
||||||
nThRef: {index: number}
|
|
||||||
): any {
|
|
||||||
depth += 1;
|
|
||||||
return children.map((item, index) => {
|
|
||||||
item = isObject(item)
|
|
||||||
? item
|
|
||||||
: {
|
|
||||||
item
|
|
||||||
};
|
|
||||||
const id = item.__id ?? guid();
|
|
||||||
|
|
||||||
return {
|
|
||||||
// id: String(item && (item as any)[self.primaryField] || `${pindex}-${depth}-${key}`),
|
|
||||||
id: String(id),
|
|
||||||
parentId: String(parentId),
|
|
||||||
key: String(`${pindex}-${depth}-${index}`),
|
|
||||||
path: `${path}${index}`,
|
|
||||||
depth: depth,
|
|
||||||
index: index,
|
|
||||||
nth: nThRef.index++,
|
|
||||||
newIndex: index,
|
|
||||||
pristine: item,
|
|
||||||
data: item,
|
|
||||||
rowSpans: {},
|
|
||||||
children:
|
|
||||||
item && Array.isArray(item.children)
|
|
||||||
? initChildren(
|
|
||||||
item.children,
|
|
||||||
depth,
|
|
||||||
index,
|
|
||||||
id,
|
|
||||||
`${path}${index}.`,
|
|
||||||
nThRef
|
|
||||||
)
|
|
||||||
: [],
|
|
||||||
expandable: !!(
|
|
||||||
(item && Array.isArray(item.children) && item.children.length) ||
|
|
||||||
(self.footable && self.footableColumns.length)
|
|
||||||
)
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function initRows(
|
function initRows(
|
||||||
rows: Array<any>,
|
rows: Array<any>,
|
||||||
getEntryId?: (entry: any, index: number) => string,
|
getEntryId?: (entry: any, index: number) => string,
|
||||||
@ -1298,7 +1335,6 @@ export const TableStore = iRendererStore
|
|||||||
/* 避免输入内容为非数组挂掉 */
|
/* 避免输入内容为非数组挂掉 */
|
||||||
rows = !Array.isArray(rows) ? [] : rows;
|
rows = !Array.isArray(rows) ? [] : rows;
|
||||||
|
|
||||||
const nThRef = {index: 0};
|
|
||||||
let arr: Array<SRow> = rows.map((item, index) => {
|
let arr: Array<SRow> = rows.map((item, index) => {
|
||||||
if (!isObject(item)) {
|
if (!isObject(item)) {
|
||||||
item = {
|
item = {
|
||||||
@ -1315,20 +1351,18 @@ export const TableStore = iRendererStore
|
|||||||
key: String(`${index}-1-${index}`),
|
key: String(`${index}-1-${index}`),
|
||||||
depth: 1, // 最大父节点默认为第一层,逐层叠加
|
depth: 1, // 最大父节点默认为第一层,逐层叠加
|
||||||
index: index,
|
index: index,
|
||||||
nth: nThRef.index++,
|
|
||||||
newIndex: index,
|
newIndex: index,
|
||||||
pristine: item,
|
pristine: item,
|
||||||
path: `${index}`,
|
path: `${index}`,
|
||||||
data: item,
|
data: item,
|
||||||
rowSpans: {},
|
rowSpans: {},
|
||||||
|
defer: !!item.defer,
|
||||||
|
loaded: false,
|
||||||
|
loading: false,
|
||||||
children:
|
children:
|
||||||
item && Array.isArray(item.children)
|
item && Array.isArray(item.children)
|
||||||
? initChildren(item.children, 1, index, id, `${index}.`, nThRef)
|
? initChildren(item.children, 1, index, id, `${index}.`)
|
||||||
: [],
|
: []
|
||||||
expandable: !!(
|
|
||||||
(item && Array.isArray(item.children) && item.children.length) ||
|
|
||||||
(self.footable && self.footableColumns.length)
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1342,7 +1376,9 @@ export const TableStore = iRendererStore
|
|||||||
}
|
}
|
||||||
|
|
||||||
replaceRow(arr, reUseRow);
|
replaceRow(arr, reUseRow);
|
||||||
self.isNested = self.rows.some(item => item.children.length);
|
self.isNested = self.rows.some(
|
||||||
|
item => item.children.length || (item.defer && !item.loaded)
|
||||||
|
);
|
||||||
|
|
||||||
// 前 20 个直接渲染,后面的按需渲染
|
// 前 20 个直接渲染,后面的按需渲染
|
||||||
if (
|
if (
|
||||||
|
@ -620,6 +620,10 @@
|
|||||||
> thead > tr > th.#{$ns}Table-primayCell,
|
> thead > tr > th.#{$ns}Table-primayCell,
|
||||||
> tbody > tr > td.#{$ns}Table-primayCell {
|
> tbody > tr > td.#{$ns}Table-primayCell {
|
||||||
white-space: nowrap; // 树形表格展示标题栏,不要换行
|
white-space: nowrap; // 树形表格展示标题栏,不要换行
|
||||||
|
|
||||||
|
> .#{$ns}Spinner {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -864,6 +868,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&-retryBtn {
|
||||||
|
color: var(--Form-feedBack-color);
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover {
|
||||||
|
color: var(--Form-feedBack-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&-expandBtn,
|
&-expandBtn,
|
||||||
&-expandBtn2 {
|
&-expandBtn2 {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -197,6 +197,8 @@ register('de-DE', {
|
|||||||
'Options.editLabel': 'Bearbeiten {{label}}',
|
'Options.editLabel': 'Bearbeiten {{label}}',
|
||||||
'Options.label': 'Option',
|
'Options.label': 'Option',
|
||||||
'Options.createFailed': 'Erstellen fehlgeschlagen',
|
'Options.createFailed': 'Erstellen fehlgeschlagen',
|
||||||
|
'Options.retry':
|
||||||
|
"Laden fehlgeschlagen '{{reason}}', klicken Sie auf Wiederholen",
|
||||||
'placeholder.empty': '<Empty>',
|
'placeholder.empty': '<Empty>',
|
||||||
'placeholder.enter': 'Eingabe',
|
'placeholder.enter': 'Eingabe',
|
||||||
'placeholder.noData': 'Keine Daten',
|
'placeholder.noData': 'Keine Daten',
|
||||||
|
@ -189,6 +189,7 @@ register('en-US', {
|
|||||||
'Options.editLabel': 'Edit {{label}}',
|
'Options.editLabel': 'Edit {{label}}',
|
||||||
'Options.label': 'option',
|
'Options.label': 'option',
|
||||||
'Options.createFailed': 'create failed, please check',
|
'Options.createFailed': 'create failed, please check',
|
||||||
|
'Options.retry': "Loading failed '{{reason}}', click retry",
|
||||||
'placeholder.empty': '<Empty>',
|
'placeholder.empty': '<Empty>',
|
||||||
'placeholder.enter': 'Enter',
|
'placeholder.enter': 'Enter',
|
||||||
'placeholder.noData': 'No data',
|
'placeholder.noData': 'No data',
|
||||||
|
@ -194,6 +194,7 @@ register('zh-CN', {
|
|||||||
'Options.editLabel': '编辑{{label}}',
|
'Options.editLabel': '编辑{{label}}',
|
||||||
'Options.label': '选项',
|
'Options.label': '选项',
|
||||||
'Options.createFailed': '新增失败,请仔细检查',
|
'Options.createFailed': '新增失败,请仔细检查',
|
||||||
|
'Options.retry': '加载失败「{{reason}}」,点击重试',
|
||||||
'placeholder.empty': '<空>',
|
'placeholder.empty': '<空>',
|
||||||
'placeholder.enter': '请输入',
|
'placeholder.enter': '请输入',
|
||||||
'placeholder.noData': '暂无数据',
|
'placeholder.noData': '暂无数据',
|
||||||
|
@ -132,6 +132,11 @@ export interface CRUDCommonSchema extends BaseSchema, SpinnerExtraProps {
|
|||||||
*/
|
*/
|
||||||
api?: SchemaApi;
|
api?: SchemaApi;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 懒加载 API,当行数据中用 defer: true 标记了,则其孩子节点将会用这个 API 来拉取数据。
|
||||||
|
*/
|
||||||
|
deferApi?: SchemaApi;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 批量操作
|
* 批量操作
|
||||||
*/
|
*/
|
||||||
|
@ -9,7 +9,7 @@ import {
|
|||||||
buildTrackExpression,
|
buildTrackExpression,
|
||||||
evalTrackExpression
|
evalTrackExpression
|
||||||
} from 'amis-core';
|
} from 'amis-core';
|
||||||
import {BadgeObject, Checkbox, Icon} from 'amis-ui';
|
import {BadgeObject, Checkbox, Icon, Spinner} from 'amis-ui';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
export interface CellProps extends ThemeProps {
|
export interface CellProps extends ThemeProps {
|
||||||
@ -32,6 +32,7 @@ export interface CellProps extends ThemeProps {
|
|||||||
popOverContainer?: any;
|
popOverContainer?: any;
|
||||||
quickEditFormRef: any;
|
quickEditFormRef: any;
|
||||||
onImageEnlarge?: any;
|
onImageEnlarge?: any;
|
||||||
|
translate: (key: string, ...args: Array<any>) => string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Cell({
|
export default function Cell({
|
||||||
@ -51,7 +52,8 @@ export default function Cell({
|
|||||||
onDragStart,
|
onDragStart,
|
||||||
popOverContainer,
|
popOverContainer,
|
||||||
quickEditFormRef,
|
quickEditFormRef,
|
||||||
onImageEnlarge
|
onImageEnlarge,
|
||||||
|
translate: __
|
||||||
}: CellProps) {
|
}: CellProps) {
|
||||||
if (column.name && item.rowSpans[column.name] === 0) {
|
if (column.name && item.rowSpans[column.name] === 0) {
|
||||||
return null;
|
return null;
|
||||||
@ -134,7 +136,18 @@ export default function Cell({
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
prefix.push(
|
prefix.push(
|
||||||
item.expandable ? (
|
item.loading ? (
|
||||||
|
<Spinner key="loading" size="sm" show />
|
||||||
|
) : item.error ? (
|
||||||
|
<a
|
||||||
|
className={cx('Table-retryBtn')}
|
||||||
|
key="retryBtn"
|
||||||
|
onClick={item.resetDefered}
|
||||||
|
data-tooltip={__('Options.retry', {reason: item.error})}
|
||||||
|
>
|
||||||
|
<Icon icon="retry" className="icon" />
|
||||||
|
</a>
|
||||||
|
) : item.expandable ? (
|
||||||
<a
|
<a
|
||||||
key="expandBtn2"
|
key="expandBtn2"
|
||||||
className={cx('Table-expandBtn2', item.expanded ? 'is-active' : '')}
|
className={cx('Table-expandBtn2', item.expanded ? 'is-active' : '')}
|
||||||
@ -169,7 +182,13 @@ export default function Cell({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
return [prefix, affix, addtionalClassName];
|
return [prefix, affix, addtionalClassName];
|
||||||
}, [item.expandable, item.expanded, column.isPrimary]);
|
}, [
|
||||||
|
item.expandable,
|
||||||
|
item.expanded,
|
||||||
|
item.error,
|
||||||
|
item.loading,
|
||||||
|
column.isPrimary
|
||||||
|
]);
|
||||||
|
|
||||||
// 根据条件缓存 data,避免孩子重复渲染
|
// 根据条件缓存 data,避免孩子重复渲染
|
||||||
const hasCustomTrackExpression =
|
const hasCustomTrackExpression =
|
||||||
|
@ -60,6 +60,8 @@ export class TableRow extends React.PureComponent<
|
|||||||
depth: number;
|
depth: number;
|
||||||
expandable: boolean;
|
expandable: boolean;
|
||||||
appeard?: boolean;
|
appeard?: boolean;
|
||||||
|
loading?: boolean;
|
||||||
|
error?: string;
|
||||||
checkdisable: boolean;
|
checkdisable: boolean;
|
||||||
trRef?: React.Ref<any>;
|
trRef?: React.Ref<any>;
|
||||||
isNested?: boolean;
|
isNested?: boolean;
|
||||||
@ -362,6 +364,8 @@ export default observer((props: TableRowProps) => {
|
|||||||
depth={item.depth}
|
depth={item.depth}
|
||||||
expandable={item.expandable}
|
expandable={item.expandable}
|
||||||
checkdisable={item.checkdisable}
|
checkdisable={item.checkdisable}
|
||||||
|
loading={item.loading}
|
||||||
|
error={item.error}
|
||||||
// data 在 TableRow 里面没有使用,这里写上是为了当列数据变化的时候 TableRow 重新渲染,
|
// data 在 TableRow 里面没有使用,这里写上是为了当列数据变化的时候 TableRow 重新渲染,
|
||||||
// 不是 item.locals 的原因是 item.locals 会变化多次,比如父级上下文变化也会进来,但是 item.data 只会变化一次。
|
// 不是 item.locals 的原因是 item.locals 会变化多次,比如父级上下文变化也会进来,但是 item.data 只会变化一次。
|
||||||
data={canAccessSuperData ? item.locals : item.data}
|
data={canAccessSuperData ? item.locals : item.data}
|
||||||
|
@ -7,7 +7,8 @@ import {
|
|||||||
SchemaExpression,
|
SchemaExpression,
|
||||||
position,
|
position,
|
||||||
animation,
|
animation,
|
||||||
evalExpressionWithConditionBuilder
|
evalExpressionWithConditionBuilder,
|
||||||
|
isEffectiveApi
|
||||||
} from 'amis-core';
|
} from 'amis-core';
|
||||||
import {Renderer, RendererProps} from 'amis-core';
|
import {Renderer, RendererProps} from 'amis-core';
|
||||||
import {SchemaNode, ActionObject, Schema} from 'amis-core';
|
import {SchemaNode, ActionObject, Schema} from 'amis-core';
|
||||||
@ -71,6 +72,7 @@ import ColGroup from './ColGroup';
|
|||||||
import debounce from 'lodash/debounce';
|
import debounce from 'lodash/debounce';
|
||||||
import AutoFilterForm from './AutoFilterForm';
|
import AutoFilterForm from './AutoFilterForm';
|
||||||
import Cell from './Cell';
|
import Cell from './Cell';
|
||||||
|
import {reaction} from 'mobx';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 表格列,不指定类型时默认为文本类型。
|
* 表格列,不指定类型时默认为文本类型。
|
||||||
@ -343,6 +345,11 @@ export interface TableSchema extends BaseSchema {
|
|||||||
* table layout
|
* table layout
|
||||||
*/
|
*/
|
||||||
tableLayout?: 'fixed' | 'auto';
|
tableLayout?: 'fixed' | 'auto';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 懒加载 API,当行数据中用 defer: true 标记了,则其孩子节点将会用这个 API 来拉取数据。
|
||||||
|
*/
|
||||||
|
deferApi?: SchemaApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TableProps extends RendererProps, SpinnerExtraProps {
|
export interface TableProps extends RendererProps, SpinnerExtraProps {
|
||||||
@ -640,6 +647,18 @@ export default class Table extends React.Component<TableProps, object> {
|
|||||||
|
|
||||||
formItem && isAlive(formItem) && formItem.setSubStore(store);
|
formItem && isAlive(formItem) && formItem.setSubStore(store);
|
||||||
Table.syncRows(store, this.props, undefined) && this.syncSelected();
|
Table.syncRows(store, this.props, undefined) && this.syncSelected();
|
||||||
|
|
||||||
|
this.toDispose.push(
|
||||||
|
reaction(
|
||||||
|
() =>
|
||||||
|
store
|
||||||
|
.getExpandedRows()
|
||||||
|
.filter(
|
||||||
|
row => row.defer && !row.loaded && !row.loading && !row.error
|
||||||
|
),
|
||||||
|
(rows: Array<IRow>) => rows.forEach(this.loadDeferredRow)
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static syncRows(
|
static syncRows(
|
||||||
@ -711,6 +730,34 @@ export default class Table extends React.Component<TableProps, object> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@autobind
|
||||||
|
async loadDeferredRow(row: IRow) {
|
||||||
|
const {env} = this.props;
|
||||||
|
const deferApi = row.data.deferApi || this.props.deferApi;
|
||||||
|
|
||||||
|
if (!isEffectiveApi(deferApi)) {
|
||||||
|
throw new Error('deferApi is required');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
row.markLoading(true);
|
||||||
|
|
||||||
|
const response = await env.fetcher(deferApi, row.locals);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(response.msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
row.setDeferData(response.data);
|
||||||
|
row.markLoaded(true);
|
||||||
|
row.setError('');
|
||||||
|
} catch (e) {
|
||||||
|
row.setError(e.message);
|
||||||
|
env.notify('error', e.message);
|
||||||
|
} finally {
|
||||||
|
row.markLoading(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 自动设置表格高度占满界面剩余区域
|
* 自动设置表格高度占满界面剩余区域
|
||||||
* 用 css 实现有点麻烦,要改很多结构,所以先用 dom hack 了,避免对之前的功能有影响
|
* 用 css 实现有点麻烦,要改很多结构,所以先用 dom hack 了,避免对之前的功能有影响
|
||||||
@ -2024,7 +2071,8 @@ export default class Table extends React.Component<TableProps, object> {
|
|||||||
checkOnItemClick,
|
checkOnItemClick,
|
||||||
popOverContainer,
|
popOverContainer,
|
||||||
canAccessSuperData,
|
canAccessSuperData,
|
||||||
itemBadge
|
itemBadge,
|
||||||
|
translate
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -2047,6 +2095,7 @@ export default class Table extends React.Component<TableProps, object> {
|
|||||||
popOverContainer={this.getPopOverContainer}
|
popOverContainer={this.getPopOverContainer}
|
||||||
quickEditFormRef={this.subFormRef}
|
quickEditFormRef={this.subFormRef}
|
||||||
onImageEnlarge={this.handleImageEnlarge}
|
onImageEnlarge={this.handleImageEnlarge}
|
||||||
|
translate={translate}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user