mirror of
https://gitee.com/baidu/amis.git
synced 2024-11-29 18:39:05 +08:00
feat: Table原子组件
This commit is contained in:
parent
0080d01487
commit
422376dec7
901
docs/zh-CN/components/table-v2.md
Executable file
901
docs/zh-CN/components/table-v2.md
Executable file
@ -0,0 +1,901 @@
|
||||
---
|
||||
title: Table v2 表格
|
||||
description:
|
||||
type: 0
|
||||
group: ⚙ 组件
|
||||
menuName: Table 表格
|
||||
icon:
|
||||
order: 67
|
||||
---
|
||||
|
||||
表格展示,不支持配置初始化接口初始化数据域,所以需要搭配类似像`Service`这样的,具有配置接口初始化数据域功能的组件,或者手动进行数据域初始化,然后通过`source`属性,获取数据链中的数据,完成数据展示。
|
||||
|
||||
## 基本用法
|
||||
|
||||
```schema: scope="body"
|
||||
{
|
||||
"type": "service",
|
||||
"api": "/api/sample?perPage=5",
|
||||
"body": [
|
||||
{
|
||||
"type": "table-v2",
|
||||
"title": "表格标题",
|
||||
"source": "$rows",
|
||||
"columns": [
|
||||
{
|
||||
"title": "Engine",
|
||||
"key": "engine"
|
||||
},
|
||||
{
|
||||
"title": "Version",
|
||||
"key": "version"
|
||||
},
|
||||
{
|
||||
"title": "Browser",
|
||||
"key": "browser"
|
||||
},
|
||||
{
|
||||
"title": "Operation",
|
||||
"key": "operation",
|
||||
"type": "button",
|
||||
"label": "删除",
|
||||
"size": "sm"
|
||||
}
|
||||
],
|
||||
"footer": "表格Footer"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 可选择 - 多选
|
||||
|
||||
```schema: scope="body"
|
||||
{
|
||||
"type": "service",
|
||||
"api": "/api/sample?perPage=5",
|
||||
"body": [
|
||||
{
|
||||
"type": "table-v2",
|
||||
"source": "$rows",
|
||||
"rowSelection": {
|
||||
"type": "checkbox",
|
||||
"keyField": "id"
|
||||
},
|
||||
"columns": [
|
||||
{
|
||||
"title": "Engine",
|
||||
"key": "engine"
|
||||
},
|
||||
{
|
||||
"title": "Version",
|
||||
"key": "version"
|
||||
},
|
||||
{
|
||||
"title": "Browser",
|
||||
"key": "browser"
|
||||
},
|
||||
{
|
||||
"title": "Operation",
|
||||
"key": "operation",
|
||||
"type": "button",
|
||||
"label": "删除",
|
||||
"size": "sm"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 可选择 - 单选
|
||||
|
||||
```schema: scope="body"
|
||||
{
|
||||
"type": "service",
|
||||
"api": "/api/sample?perPage=5",
|
||||
"body": [
|
||||
{
|
||||
"type": "table-v2",
|
||||
"source": "$rows",
|
||||
"rowSelection": {
|
||||
"type": "radio",
|
||||
"keyField": "id",
|
||||
"disableOn": "this.record.id === 1"
|
||||
},
|
||||
"columns": [
|
||||
{
|
||||
"title": "Engine",
|
||||
"key": "engine"
|
||||
},
|
||||
{
|
||||
"title": "Version",
|
||||
"key": "version"
|
||||
},
|
||||
{
|
||||
"title": "Browser",
|
||||
"key": "browser"
|
||||
},
|
||||
{
|
||||
"title": "Operation",
|
||||
"key": "operation",
|
||||
"type": "button",
|
||||
"label": "删除",
|
||||
"size": "sm"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 筛选和排序
|
||||
|
||||
```schema: scope="body"
|
||||
{
|
||||
"type": "service",
|
||||
"api": "/api/sample?perPage=5",
|
||||
"body": [
|
||||
{
|
||||
"type": "table-v2",
|
||||
"source": "$rows",
|
||||
"columns": [
|
||||
{
|
||||
"title": "Engine",
|
||||
"key": "engine",
|
||||
"sorter": true,
|
||||
"filterMultiple": true,
|
||||
"filters": [
|
||||
{
|
||||
"text": "Joe",
|
||||
"value": "Joe"
|
||||
},
|
||||
{
|
||||
"text": "Jim",
|
||||
"value": "Jim"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Version",
|
||||
"key": "version",
|
||||
"sorter": true,
|
||||
"width": 100
|
||||
},
|
||||
{
|
||||
"title": "Browser",
|
||||
"key": "browser",
|
||||
"filters": [
|
||||
{
|
||||
"text": "Joe",
|
||||
"value": "Joe"
|
||||
},
|
||||
{
|
||||
"text": "Jim",
|
||||
"value": "Jim"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 带边框
|
||||
|
||||
```schema: scope="body"
|
||||
{
|
||||
"type": "service",
|
||||
"api": "/api/sample?perPage=5",
|
||||
"body": [
|
||||
{
|
||||
"type": "table-v2",
|
||||
"source": "$rows",
|
||||
"bordered": true,
|
||||
"title": "标题",
|
||||
"footer": "Footer",
|
||||
"columns": [
|
||||
{
|
||||
"title": "Engine",
|
||||
"key": "engine"
|
||||
},
|
||||
{
|
||||
"title": "Version",
|
||||
"key": "version"
|
||||
},
|
||||
{
|
||||
"title": "Browser",
|
||||
"key": "browser"
|
||||
},
|
||||
{
|
||||
"title": "Operation",
|
||||
"key": "operation",
|
||||
"type": "button",
|
||||
"label": "删除",
|
||||
"size": "sm"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 可展开
|
||||
|
||||
```schema: scope="body"
|
||||
{
|
||||
"type": "service",
|
||||
"api": "/api/sample?perPage=5",
|
||||
"body": [
|
||||
{
|
||||
"type": "table-v2",
|
||||
"source": "$rows",
|
||||
"columns": [
|
||||
{
|
||||
"title": "Engine",
|
||||
"key": "engine"
|
||||
},
|
||||
{
|
||||
"title": "Version",
|
||||
"key": "version"
|
||||
},
|
||||
{
|
||||
"title": "Browser",
|
||||
"key": "browser"
|
||||
},
|
||||
{
|
||||
"title": "Operation",
|
||||
"key": "operation",
|
||||
"type": "button",
|
||||
"label": "删除",
|
||||
"size": "sm"
|
||||
}
|
||||
],
|
||||
"expandable": {
|
||||
"expandableOn": "this.id === 1 || this.id === 3",
|
||||
"keyField": "id",
|
||||
"type": "tpl",
|
||||
"html": "<div class=\"test\">测试测试</div>",
|
||||
"expandedRowClassNameExpr": "<%= data.rowIndex % 2 ? 'bg-success' : '' %>",
|
||||
"expandedRowKeys": ["3"]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 表格行/列合并
|
||||
|
||||
```schema: scope="body"
|
||||
{
|
||||
"type": "service",
|
||||
"api": "/api/sample?perPage=10",
|
||||
"body": [
|
||||
{
|
||||
"type": "table-v2",
|
||||
"source": "$rows",
|
||||
"columns": [
|
||||
{
|
||||
"title": "Engine",
|
||||
"key": "engine"
|
||||
},
|
||||
{
|
||||
"title": "Version",
|
||||
"key": "version",
|
||||
"rowSpanExpr": "<%= data.rowIndex === 2 ? 2 : 0 %>"
|
||||
},
|
||||
{
|
||||
"title": "Browser",
|
||||
"key": "browser"
|
||||
},
|
||||
{
|
||||
"title": "Badge",
|
||||
"key": "badgeText",
|
||||
"colSpanExpr": "<%= data.rowIndex === 6 ? 3 : 0 %>"
|
||||
},
|
||||
{
|
||||
"title": "Grade",
|
||||
"key": "grade"
|
||||
},
|
||||
{
|
||||
"title": "Platform",
|
||||
"key": "platform"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 固定表头
|
||||
|
||||
```schema: scope="body"
|
||||
{
|
||||
"type": "service",
|
||||
"api": "/api/sample?perPage=10",
|
||||
"body": [
|
||||
{
|
||||
"type": "table-v2",
|
||||
"source": "$rows",
|
||||
"scroll": {"y" : 200},
|
||||
"columns": [
|
||||
{
|
||||
"title": "Engine",
|
||||
"key": "engine"
|
||||
},
|
||||
{
|
||||
"title": "Grade",
|
||||
"key": "grade"
|
||||
},
|
||||
{
|
||||
"title": "Platform",
|
||||
"key": "platform"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 固定列
|
||||
|
||||
```schema: scope="body"
|
||||
{
|
||||
"type": "service",
|
||||
"api": "/api/sample?perPage=6",
|
||||
"body": [
|
||||
{
|
||||
"type": "table-v2",
|
||||
"source": "$rows",
|
||||
"scroll": {"x": 1000},
|
||||
"columns": [
|
||||
{
|
||||
"title": "Engine",
|
||||
"key": "engine",
|
||||
"fixed": "left",
|
||||
"width": 100
|
||||
},
|
||||
{
|
||||
"title": "Version",
|
||||
"key": "version",
|
||||
"fixed": "left",
|
||||
"width": 100
|
||||
},
|
||||
{
|
||||
"title": "Browser",
|
||||
"key": "browser"
|
||||
},
|
||||
{
|
||||
"title": "Badge",
|
||||
"key": "badgeText"
|
||||
},
|
||||
{
|
||||
"title": "Grade",
|
||||
"key": "grade"
|
||||
},
|
||||
{
|
||||
"title": "Platform",
|
||||
"key": "platform",
|
||||
"fixed": "right"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 固定头和列
|
||||
|
||||
```schema: scope="body"
|
||||
{
|
||||
"type": "service",
|
||||
"api": "/api/sample?perPage=10",
|
||||
"body": [
|
||||
{
|
||||
"type": "table-v2",
|
||||
"source": "$rows",
|
||||
"scroll": {"x": 1000, "y": 200},
|
||||
"columns": [
|
||||
{
|
||||
"title": "Engine",
|
||||
"key": "engine",
|
||||
"fixed": "left",
|
||||
"width": 100
|
||||
},
|
||||
{
|
||||
"title": "Version",
|
||||
"key": "version",
|
||||
"fixed": "left",
|
||||
"width": 100
|
||||
},
|
||||
{
|
||||
"title": "Browser",
|
||||
"key": "browser"
|
||||
},
|
||||
{
|
||||
"title": "Badge",
|
||||
"key": "badgeText"
|
||||
},
|
||||
{
|
||||
"title": "Grade",
|
||||
"key": "grade"
|
||||
},
|
||||
{
|
||||
"title": "Platform",
|
||||
"key": "platform",
|
||||
"fixed": "right"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 表头分组
|
||||
|
||||
```schema: scope="body"
|
||||
{
|
||||
"type": "service",
|
||||
"api": "/api/sample?perPage=10",
|
||||
"body": [
|
||||
{
|
||||
"type": "table-v2",
|
||||
"source": "$rows",
|
||||
"scroll": {"y": 200},
|
||||
"columns": [
|
||||
{
|
||||
"title": "Engine",
|
||||
"key": "engine",
|
||||
},
|
||||
{
|
||||
"title": "Version",
|
||||
"key": "version",
|
||||
"fixed": "left"
|
||||
},
|
||||
{
|
||||
"title": "Grade",
|
||||
"key": "grade"
|
||||
},
|
||||
{
|
||||
"title": "Grade1",
|
||||
"key": "grade1",
|
||||
"children": [
|
||||
{
|
||||
"title": "Browser",
|
||||
"key": "browser"
|
||||
},
|
||||
{
|
||||
"title": "Badge",
|
||||
"key": "badgeText",
|
||||
"children": [
|
||||
{
|
||||
"title": "ID",
|
||||
"key": "id"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Platform",
|
||||
"key": "platform",
|
||||
"fixed": "right"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 拖拽排序
|
||||
|
||||
```schema: scope="body"
|
||||
{
|
||||
"type": "service",
|
||||
"api": "/api/sample?perPage=5",
|
||||
"body": [
|
||||
{
|
||||
"type": "table-v2",
|
||||
"source": "$rows",
|
||||
"draggable": true,
|
||||
"columns": [
|
||||
{
|
||||
"title": "Engine",
|
||||
"key": "engine",
|
||||
},
|
||||
{
|
||||
"title": "Version",
|
||||
"key": "version",
|
||||
"fixed": "left"
|
||||
},
|
||||
{
|
||||
"title": "Grade",
|
||||
"key": "grade"
|
||||
},
|
||||
{
|
||||
"title": "Browser",
|
||||
"key": "browser"
|
||||
},
|
||||
{
|
||||
"title": "Badge",
|
||||
"key": "badgeText",
|
||||
"children": [
|
||||
{
|
||||
"title": "ID",
|
||||
"key": "id"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Platform",
|
||||
"key": "platform",
|
||||
"fixed": "right"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 顶部总结栏
|
||||
|
||||
```schema: scope="body"
|
||||
{
|
||||
"type": "service",
|
||||
"api": "/api/sample?perPage=10",
|
||||
"body": [
|
||||
{
|
||||
"type": "table-v2",
|
||||
"source": "$rows",
|
||||
"scroll": {"y": 200},
|
||||
"columns": [
|
||||
{
|
||||
"title": "Engine",
|
||||
"key": "engine",
|
||||
},
|
||||
{
|
||||
"title": "Version",
|
||||
"key": "version"
|
||||
},
|
||||
{
|
||||
"title": "Grade",
|
||||
"key": "grade"
|
||||
},
|
||||
{
|
||||
"title": "Browser",
|
||||
"key": "browser"
|
||||
},
|
||||
{
|
||||
"title": "Badge",
|
||||
"key": "badgeText"
|
||||
},
|
||||
{
|
||||
"title": "Platform",
|
||||
"key": "platform"
|
||||
}
|
||||
],
|
||||
"headSummary": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "总计"
|
||||
},
|
||||
{
|
||||
"type": "tpl",
|
||||
"tpl": "测试测试",
|
||||
"colSpan": 5
|
||||
}
|
||||
],
|
||||
"rowSelection": {
|
||||
"type": "checkbox",
|
||||
"keyField": "id"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 尾部总结栏
|
||||
|
||||
```schema: scope="body"
|
||||
{
|
||||
"type": "service",
|
||||
"api": "/api/sample?perPage=10",
|
||||
"body": [
|
||||
{
|
||||
"type": "table-v2",
|
||||
"source": "$rows",
|
||||
"bordered": true,
|
||||
"scroll": {"y": 200, "x": 1000},
|
||||
"columns": [
|
||||
{
|
||||
"title": "Engine",
|
||||
"key": "engine",
|
||||
"fixed": "left"
|
||||
},
|
||||
{
|
||||
"title": "Version",
|
||||
"key": "version"
|
||||
},
|
||||
{
|
||||
"title": "Grade",
|
||||
"key": "grade"
|
||||
},
|
||||
{
|
||||
"title": "Browser",
|
||||
"key": "browser"
|
||||
},
|
||||
{
|
||||
"title": "Badge",
|
||||
"key": "badgeText"
|
||||
},
|
||||
{
|
||||
"title": "Platform",
|
||||
"key": "platform"
|
||||
}
|
||||
],
|
||||
"footSummary": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "总计",
|
||||
"fixed": 'left'
|
||||
},
|
||||
{
|
||||
"type": "tpl",
|
||||
"tpl": "测试测试",
|
||||
"colSpan": 5
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 调整列宽
|
||||
|
||||
```schema: scope="body"
|
||||
{
|
||||
"type": "service",
|
||||
"api": "/api/sample?perPage=6",
|
||||
"body": [
|
||||
{
|
||||
"type": "table-v2",
|
||||
"source": "$rows",
|
||||
"bordered": true,
|
||||
"scroll": {"x": 1000},
|
||||
"resizable": true,
|
||||
"columns": [
|
||||
{
|
||||
"title": "Engine",
|
||||
"key": "engine",
|
||||
"width": 200,
|
||||
"align": "center"
|
||||
},
|
||||
{
|
||||
"title": "Version",
|
||||
"key": "version",
|
||||
"width": 200,
|
||||
"align": "right"
|
||||
},
|
||||
{
|
||||
"title": "Grade",
|
||||
"key": "grade",
|
||||
"width": 200
|
||||
},
|
||||
{
|
||||
"title": "Browser",
|
||||
"key": "browser",
|
||||
"width": 200
|
||||
},
|
||||
{
|
||||
"title": "Badge",
|
||||
"key": "badgeText"
|
||||
},
|
||||
{
|
||||
"title": "Platform",
|
||||
"key": "platform"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 自定义列
|
||||
|
||||
```schema: scope="body"
|
||||
{
|
||||
"type": "service",
|
||||
"api": "/api/sample?perPage=6",
|
||||
"body": [
|
||||
{
|
||||
"type": "table-v2",
|
||||
"source": "$rows",
|
||||
"columnsToggable": true,
|
||||
"title": "表格的标题",
|
||||
"bordered": true,
|
||||
"columns": [
|
||||
{
|
||||
"title": "Engine",
|
||||
"key": "engine",
|
||||
"width": 200
|
||||
},
|
||||
{
|
||||
"title": "Version",
|
||||
"key": "version",
|
||||
"width": 200
|
||||
},
|
||||
{
|
||||
"title": "Browser",
|
||||
"key": "browser",
|
||||
"width": 200,
|
||||
"children": [
|
||||
{
|
||||
"title": "Grade",
|
||||
"key": "grade",
|
||||
"width": 200
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Badge",
|
||||
"key": "badgeText"
|
||||
},
|
||||
{
|
||||
"title": "Platform",
|
||||
"key": "platform"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 数据为空
|
||||
|
||||
```schema
|
||||
{
|
||||
"type": "table-v2",
|
||||
"data": {
|
||||
"items": []
|
||||
},
|
||||
"columns": [
|
||||
{
|
||||
"title": "Engine",
|
||||
"key": "engine",
|
||||
"width": 200
|
||||
},
|
||||
{
|
||||
"title": "Version",
|
||||
"key": "version",
|
||||
"width": 200
|
||||
},
|
||||
{
|
||||
"title": "Browser",
|
||||
"key": "browser",
|
||||
"width": 200,
|
||||
"children": [
|
||||
{
|
||||
"title": "Grade",
|
||||
"key": "grade",
|
||||
"width": 200
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Platform",
|
||||
"key": "platform",
|
||||
"children": [
|
||||
{
|
||||
"title": "Badge",
|
||||
"key": "badgeText"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"placeholder": "暂无数据"
|
||||
}
|
||||
```
|
||||
|
||||
## 数据为空
|
||||
|
||||
```schema
|
||||
{
|
||||
"type": "table-v2",
|
||||
"data": {
|
||||
"items": []
|
||||
},
|
||||
"columns": [
|
||||
{
|
||||
"title": "Engine",
|
||||
"key": "engine",
|
||||
"width": 200
|
||||
},
|
||||
{
|
||||
"title": "Version",
|
||||
"key": "version",
|
||||
"width": 200
|
||||
},
|
||||
{
|
||||
"title": "Browser",
|
||||
"key": "browser",
|
||||
"width": 200,
|
||||
"children": [
|
||||
{
|
||||
"title": "Grade",
|
||||
"key": "grade",
|
||||
"width": 200
|
||||
},
|
||||
{
|
||||
"title": "Badge",
|
||||
"key": "badgeText",
|
||||
"children": [
|
||||
{
|
||||
"title": "Platform",
|
||||
"key": "platform"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"loading": true
|
||||
}
|
||||
```
|
||||
|
||||
## 树形结构
|
||||
|
||||
## 列搜索
|
||||
|
||||
## 粘性头部
|
||||
|
||||
## 表格尺寸
|
||||
|
||||
## 单元格自动省略
|
||||
|
||||
## 响应式列
|
||||
|
||||
## Footable
|
||||
|
||||
## 属性表
|
||||
|
||||
| 属性名 | 类型 | 默认值 | 说明 |
|
||||
| ---------------- | ---------------------------------------- | ------------------------- | ------------------------------------------------------------------------- |
|
||||
| type | `string` | | `"type"` 指定为 table 渲染器 |
|
||||
| title | `string` | | 标题 |
|
||||
| source | `string` | `${items}` | 数据源, 绑定当前环境变量 |
|
||||
| affixHeader | `boolean` | `true` | 是否固定表头 |
|
||||
| columnsTogglable | `auto` 或者 `boolean` | `auto` | 展示列显示开关, 自动即:列数量大于或等于 5 个时自动开启 |
|
||||
| placeholder | string | `暂无数据` | 当没数据的时候的文字提示 |
|
||||
| className | `string` | `panel-default` | 外层 CSS 类名 |
|
||||
| tableClassName | `string` | `table-db table-striped` | 表格 CSS 类名 |
|
||||
| headerClassName | `string` | `Action.md-table-header` | 顶部外层 CSS 类名 |
|
||||
| footerClassName | `string` | `Action.md-table-footer` | 底部外层 CSS 类名 |
|
||||
| toolbarClassName | `string` | `Action.md-table-toolbar` | 工具栏 CSS 类名 |
|
||||
| columns | `Array<Column>` | | 用来设置列信息 |
|
||||
| combineNum | `number` | | 自动合并单元格 |
|
||||
| itemActions | Array<[Action](./action-button)> | | 悬浮行操作按钮组 |
|
||||
| itemCheckableOn | [表达式](../../docs/concepts/expression) | | 配置当前行是否可勾选的条件,要用 [表达式](../../docs/concepts/expression) |
|
||||
| itemDraggableOn | [表达式](../../docs/concepts/expression) | | 配置当前行是否可拖拽的条件,要用 [表达式](../../docs/concepts/expression) |
|
||||
| checkOnItemClick | `boolean` | `false` | 点击数据行是否可以勾选当前行 |
|
||||
| rowClassName | `string` | | 给行添加 CSS 类名 |
|
||||
| rowClassNameExpr | [模板](../../docs/concepts/template) | | 通过模板给行添加 CSS 类名 |
|
||||
| prefixRow | `Array` | | 顶部总结行 |
|
||||
| affixRow | `Array` | | 底部总结行 |
|
||||
| itemBadge | [`BadgeSchema`](./badge) | | 行角标配置 |
|
||||
| autoFillHeight | `boolean` | | 内容区域自适应高度 |
|
||||
|
||||
## 列配置属性表
|
||||
|
||||
| 属性名 | 类型 | 默认值 | 说明 |
|
||||
| ---------- | --------------------------------------------- | ------- | ---------------- |
|
||||
| label | [模板](../../docs/concepts/template) | | 表头文本内容 |
|
||||
| name | `string` | | 通过名称关联数据 |
|
||||
| fixed | `left` \| `right` \| `none` | | 是否固定当前列 |
|
||||
| popOver | | | 弹出框 |
|
||||
| quickEdit | | | 快速编辑 |
|
||||
| copyable | `boolean` 或 `{icon: string, content:string}` | | 是否可复制 |
|
||||
| sortable | `boolean` | `false` | 是否可排序 |
|
||||
| searchable | `boolean` \| `Schema` | `false` | 是否可快速搜索 |
|
||||
| width | `number` \| `string` | 列宽 |
|
||||
| remark | | | 提示信息 |
|
@ -775,6 +775,14 @@ export const components = [
|
||||
import('../../docs/zh-CN/components/table.md').then(wrapDoc)
|
||||
)
|
||||
},
|
||||
{
|
||||
label: 'Table v2 表格',
|
||||
path: '/zh-CN/components/table-v2',
|
||||
getComponent: () =>
|
||||
import('../../docs/zh-CN/components/table-v2.md').then(
|
||||
makeMarkdownRenderer
|
||||
)
|
||||
},
|
||||
{
|
||||
label: 'Table View 表格视图',
|
||||
path: '/zh-CN/components/table-view',
|
||||
|
@ -1326,6 +1326,10 @@
|
||||
--TableCell-sortBtn--onActive-color: var(--primary);
|
||||
--TableCell-sortBtn-width: #{px2rem(8px)};
|
||||
|
||||
--Table-fixedLeftLast-boxShadow: inset 10px 0 8px -8px #00000026;
|
||||
--Table-fixedRightFirst-boxShadow: inset -10px 0 8px -8px #00000026;
|
||||
--Table-loading-padding: 30px 0px;
|
||||
|
||||
--Tabs--card-bg: #f6f8f8;
|
||||
--Tabs--card-borderTopColor: var(--borderColor);
|
||||
--Tabs--card-linkMargin: 0 10px 0 0;
|
||||
|
@ -8,6 +8,34 @@
|
||||
margin-bottom: var(--gap-sm);
|
||||
}
|
||||
|
||||
&-bordered {
|
||||
border: var(--Table-borderWidth) solid var(--Table-borderColor);
|
||||
border-collapse: inherit;
|
||||
|
||||
.#{$ns}Table-container {
|
||||
border-top: var(--Table-borderWidth) solid var(--Table-borderColor);
|
||||
}
|
||||
|
||||
.#{$ns}Table-table {
|
||||
> thead > tr > th,
|
||||
> tbody > tr > td,
|
||||
> tfoot > tr > td {
|
||||
border-right: var(--Table-borderWidth) solid var(--Table-borderColor);
|
||||
|
||||
&:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.#{$ns}Table-footer {
|
||||
border-top: var(--Table-borderWidth) solid var(--Table-borderColor);
|
||||
}
|
||||
.#{$ns}Table-title {
|
||||
border-bottom: var(--Table-borderWidth) solid var(--Table-borderColor);
|
||||
}
|
||||
}
|
||||
|
||||
&-fixedLeft,
|
||||
&-fixedRight {
|
||||
position: absolute;
|
||||
@ -99,7 +127,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
&-heading {
|
||||
&-heading,
|
||||
&-title,
|
||||
&-footer {
|
||||
background: var(--Table-heading-bg);
|
||||
padding: calc(
|
||||
(
|
||||
@ -231,7 +261,6 @@
|
||||
background: var(--Table-bg);
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
border: var(--Table-borderWidth) solid var(--Table-borderColor);
|
||||
|
||||
& th,
|
||||
& td {
|
||||
@ -603,6 +632,124 @@
|
||||
);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
> tbody > tr > td.#{$ns}Table-cell-fix-left,
|
||||
> tbody > tr > td.#{$ns}Table-cell-fix-right,
|
||||
> tfoot > tr > td.#{$ns}Table-cell-fix-left,
|
||||
> tfoot > tr > td.#{$ns}Table-cell-fix-right {
|
||||
background: #FFF;
|
||||
}
|
||||
|
||||
> tbody > tr > td.#{$ns}Table-cell-row-hover {
|
||||
background: var(--Table-onHover-bg);
|
||||
border-color: var(--Table-onHover-borderColor);
|
||||
color: var(--Table-onHover-color);
|
||||
}
|
||||
|
||||
> thead > tr > th.#{$ns}Table-cell-fix-left-last,
|
||||
> tbody > tr > td.#{$ns}Table-cell-fix-left-last,
|
||||
> tfoot > tr > td.#{$ns}Table-cell-fix-left-last {
|
||||
&:after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: -1px;
|
||||
width: 30px;
|
||||
transform: translate(100%);
|
||||
transition: box-shadow .3s;
|
||||
content: "";
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
> thead > tr > th.#{$ns}Table-cell-fix-right-first,
|
||||
> tbody > tr > td.#{$ns}Table-cell-fix-right-first,
|
||||
> tfoot > tr > td.#{$ns}Table-cell-fix-right-last {
|
||||
&:after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: -1px;
|
||||
left: 0;
|
||||
width: 30px;
|
||||
transform: translate(-100%);
|
||||
transition: box-shadow .3s;
|
||||
content: "";
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
> tbody > tr > td.#{$ns}Table-cell-expand-icon-cell {
|
||||
text-align: center;
|
||||
|
||||
.fa-minus-square,
|
||||
.fa-plus-square {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
> tbody > tr.#{$ns}Table-expanded-row > td {
|
||||
background: var(--Table-onHover-bg);
|
||||
}
|
||||
|
||||
> tfoot > tr > td {
|
||||
padding: var(--TableCell-paddingY) var(--TableCell-paddingX);
|
||||
}
|
||||
}
|
||||
|
||||
&-container {
|
||||
.#{$ns}Table-header {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.#{$ns}Table-ping-left {
|
||||
.#{$ns}Table-table {
|
||||
> thead > tr > th.#{$ns}Table-cell-fix-left-last,
|
||||
> tbody > tr > td.#{$ns}Table-cell-fix-left-last,
|
||||
> tfoot > tr > td.#{$ns}Table-cell-fix-left-last {
|
||||
&:after {
|
||||
box-shadow: var(--Table-fixedLeftLast-boxShadow);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.#{$ns}Table-ping-right {
|
||||
.#{$ns}Table-table {
|
||||
> thead > tr > th.#{$ns}Table-cell-fix-right-first,
|
||||
> tbody > tr > td.#{$ns}Table-cell-fix-right-first,
|
||||
> tfoot > tr > td.#{$ns}Table-cell-fix-right-first {
|
||||
&:after {
|
||||
box-shadow: var(--Table-fixedRightFirst-boxShadow);
|
||||
}
|
||||
}
|
||||
|
||||
> thead > tr > th.#{$ns}Table-cell-fix-right-first {
|
||||
border-right: var(--Table-thead-borderWidth) solid var(--Table-thead-borderColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.#{$ns}Table-resizable {
|
||||
.#{$ns}Table-table {
|
||||
> thead > tr > th {
|
||||
position: relative;
|
||||
|
||||
.#{$ns}Table-thead-resizable {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
cursor: col-resize;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.#{$ns}Table-loading {
|
||||
padding: var(--Table-loading-padding);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&Cell-sortBtn {
|
||||
@ -658,6 +805,9 @@
|
||||
color: var(--TableCell-sortBtn--onActive-color);
|
||||
}
|
||||
}
|
||||
&:not(:last-child) {
|
||||
right: calc(var(--TableCell-paddingX) - var(--TableCell-sortBtn-width) / 2 + 15px);
|
||||
}
|
||||
}
|
||||
|
||||
&Cell-searchBtn {
|
||||
@ -753,6 +903,20 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.#{$ns}DropDown-multiple-menu {
|
||||
text-align: center;
|
||||
border-top: 1px solid var(--Table-borderColor);
|
||||
|
||||
.#{$ns}Button {
|
||||
margin: 0 5px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-itemActions-wrap {
|
||||
|
@ -200,6 +200,7 @@ export type SchemaType =
|
||||
| 'switch'
|
||||
| 'table'
|
||||
| 'static-table' // 这个几个跟表单项同名,再form下面用必须带前缀 static-
|
||||
| 'table-v2'
|
||||
| 'tabs'
|
||||
| 'html'
|
||||
| 'tpl'
|
||||
|
@ -58,6 +58,7 @@ import TableSelection from './TableSelection';
|
||||
import TreeSelection from './TreeSelection';
|
||||
import AssociatedSelection from './AssociatedSelection';
|
||||
import PullRefresh from './PullRefresh';
|
||||
import Table from './table';
|
||||
|
||||
export {
|
||||
NotFound,
|
||||
@ -119,5 +120,6 @@ export {
|
||||
NumberInput,
|
||||
ArrayInput,
|
||||
AnchorNav,
|
||||
PullRefresh
|
||||
PullRefresh,
|
||||
Table
|
||||
};
|
||||
|
76
src/components/table/Cell.tsx
Normal file
76
src/components/table/Cell.tsx
Normal file
@ -0,0 +1,76 @@
|
||||
/**
|
||||
* @file table/BodyCell
|
||||
* @author fex
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import {themeable, ThemeProps} from '../../theme';
|
||||
import {LocaleProps, localeable} from '../../locale';
|
||||
import {ColumnProps} from './index';
|
||||
|
||||
const zIndex = 1;
|
||||
|
||||
export interface Props extends ThemeProps, LocaleProps {
|
||||
fixed?: string | boolean; // left | right
|
||||
rowSpan?: number | any;
|
||||
colSpan?: number | any;
|
||||
key?: string | number;
|
||||
className?: string;
|
||||
children?: any;
|
||||
tagName?: string;
|
||||
style?: Object;
|
||||
column?: ColumnProps
|
||||
}
|
||||
|
||||
export class BodyCell extends React.Component<Props> {
|
||||
static defaultProps = {
|
||||
fixed: '',
|
||||
rowSpan: null,
|
||||
colSpan: null
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
fixed,
|
||||
rowSpan,
|
||||
colSpan,
|
||||
key,
|
||||
children,
|
||||
className,
|
||||
tagName,
|
||||
style,
|
||||
column,
|
||||
classnames: cx
|
||||
} = this.props;
|
||||
|
||||
if (tagName === 'TH') {
|
||||
return (
|
||||
<th
|
||||
key={key || null}
|
||||
rowSpan={rowSpan && rowSpan > 1 ? rowSpan : null}
|
||||
colSpan={colSpan && colSpan > 1 ? colSpan : null}
|
||||
className={cx('Table-cell', className, {
|
||||
[cx(`Table-cell-fix-${fixed}`)] : fixed
|
||||
})}
|
||||
style={fixed ? {position: 'sticky', zIndex} : style}
|
||||
>{children}</th>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<td
|
||||
key={key || null}
|
||||
rowSpan={rowSpan && rowSpan > 1 ? rowSpan : null}
|
||||
colSpan={colSpan && colSpan > 1 ? colSpan : null}
|
||||
className={cx('Table-cell', className, {
|
||||
[cx(`Table-cell-fix-${fixed}`)] : fixed,
|
||||
[`text-${column?.align}`] : column?.align
|
||||
})}
|
||||
style={fixed ? {position: 'sticky', zIndex} : {}}
|
||||
>{children}</td>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(localeable(BodyCell));
|
211
src/components/table/HeadCellFilter.tsx
Normal file
211
src/components/table/HeadCellFilter.tsx
Normal file
@ -0,0 +1,211 @@
|
||||
/**
|
||||
* @file table/HeadCellFilter
|
||||
* @author fex
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import {findDOMNode} from 'react-dom';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
|
||||
import {themeable, ThemeProps} from '../../theme';
|
||||
import {LocaleProps, localeable} from '../../locale';
|
||||
import Overlay from '../Overlay';
|
||||
import PopOver from '../PopOver';
|
||||
import CheckBox from '../Checkbox';
|
||||
import Button from '../Button';
|
||||
import {Icon} from '../icons';
|
||||
|
||||
export interface Props extends ThemeProps, LocaleProps {
|
||||
column: any;
|
||||
popOverContainer?: () => Element | Text | null;
|
||||
onFilter?: Function;
|
||||
onQuery?: Function;
|
||||
filteredValue?: Array<string>;
|
||||
filterMultiple?: boolean;
|
||||
}
|
||||
|
||||
export interface OptionProps {
|
||||
text: string;
|
||||
value: string;
|
||||
selected?: boolean;
|
||||
children?: Array<OptionProps>;
|
||||
}
|
||||
|
||||
export interface State {
|
||||
options: Array<OptionProps>;
|
||||
isOpened: boolean;
|
||||
filteredValue: Array<string>;
|
||||
}
|
||||
|
||||
export class HeadCellFilter extends React.Component<Props, State> {
|
||||
static defaultProps = {
|
||||
filteredValue: [],
|
||||
filterMultiple: false
|
||||
};
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
options: [],
|
||||
isOpened: false,
|
||||
filteredValue: props.filteredValue || []
|
||||
}
|
||||
|
||||
this.openLayer = this.openLayer.bind(this);
|
||||
this.closeLayer = this.closeLayer.bind(this);
|
||||
}
|
||||
|
||||
alterOptions(options: Array<any>) {
|
||||
const {column} = this.props;
|
||||
|
||||
options = options.map(option => ({
|
||||
...option,
|
||||
selected: this.state.filteredValue.indexOf(option.value) > -1
|
||||
}));
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const {column} = this.props;
|
||||
if (column.filters && column.filters.length > 0) {
|
||||
this.setState({options: this.alterOptions(column.filters)});
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: Props, prevState: State) {
|
||||
const {column} = this.props;
|
||||
if (column.filters && column.filters.length > 0
|
||||
&& !isEqual(prevState.filteredValue, this.state.filteredValue)) {
|
||||
this.setState({options: this.alterOptions(column.filters)});
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {isOpened, options} = this.state;
|
||||
const {
|
||||
column,
|
||||
popOverContainer,
|
||||
classnames: cx,
|
||||
classPrefix: ns
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<span
|
||||
className={cx(
|
||||
`${ns}TableCell-filterBtn`,
|
||||
column.filtered || options && options.some((item: any) => item.selected) ? 'is-active' : ''
|
||||
)}
|
||||
>
|
||||
<span onClick={this.openLayer}>
|
||||
<Icon icon="column-filter" className="icon" />
|
||||
</span>
|
||||
{
|
||||
isOpened ? (
|
||||
<Overlay
|
||||
container={popOverContainer || (() => findDOMNode(this))}
|
||||
placement="left-bottom-left-top right-bottom-right-top"
|
||||
target={
|
||||
popOverContainer ? () => findDOMNode(this) : null
|
||||
}
|
||||
show
|
||||
>
|
||||
<PopOver
|
||||
classPrefix={ns}
|
||||
onHide={this.closeLayer}
|
||||
className={cx(
|
||||
`${ns}TableCell-filterPopOver`
|
||||
)}
|
||||
overlay
|
||||
>
|
||||
{options && options.length > 0 ? (
|
||||
<ul className={cx('DropDown-menu')}>
|
||||
{!column.filterMultiple
|
||||
? options.map((option: any, index) => (
|
||||
<li
|
||||
key={index}
|
||||
className={cx({
|
||||
'is-active': option.selected
|
||||
})}
|
||||
onClick={this.handleClick.bind(this, option.value)}
|
||||
>
|
||||
{option.text}
|
||||
</li>
|
||||
))
|
||||
: options.map((option: any, index) => (
|
||||
<li key={index}>
|
||||
<CheckBox
|
||||
classPrefix={ns}
|
||||
onChange={this.handleCheck.bind(this, option.value)}
|
||||
checked={option.selected}
|
||||
>
|
||||
{option.text}
|
||||
</CheckBox>
|
||||
</li>
|
||||
))}
|
||||
{column.filterMultiple ? (
|
||||
<li
|
||||
key="DropDown-multiple-menu"
|
||||
className={cx('DropDown-multiple-menu')}
|
||||
>
|
||||
<Button
|
||||
size={'xs'}
|
||||
level={'primary'}
|
||||
onClick={this.handleConfirmClick.bind(this)}
|
||||
>确定</Button>
|
||||
<Button
|
||||
size={'xs'}
|
||||
onClick={this.handleCancelClick.bind(this)}
|
||||
>取消</Button>
|
||||
</li>
|
||||
) : null}
|
||||
</ul>
|
||||
) : null}
|
||||
</PopOver>
|
||||
</Overlay>)
|
||||
: null
|
||||
}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
openLayer() {
|
||||
this.setState({isOpened: true});
|
||||
}
|
||||
|
||||
closeLayer() {
|
||||
this.setState({isOpened: false});
|
||||
}
|
||||
|
||||
handleClick(value: string) {
|
||||
const {onQuery, column} = this.props;
|
||||
|
||||
this.setState({filteredValue: [value]});
|
||||
|
||||
onQuery && onQuery({[column.key] : value});
|
||||
this.closeLayer();
|
||||
}
|
||||
|
||||
handleCheck(value: string) {
|
||||
const filteredValue = this.state.filteredValue;
|
||||
if (value) {
|
||||
this.setState({filteredValue: [...filteredValue, value]});
|
||||
} else {
|
||||
this.setState({filteredValue: filteredValue.filter(v => v !== value)});
|
||||
}
|
||||
}
|
||||
|
||||
handleConfirmClick() {
|
||||
const {onQuery, column} = this.props;
|
||||
onQuery && onQuery({[column.key] : this.state.filteredValue});
|
||||
this.closeLayer();
|
||||
}
|
||||
|
||||
handleCancelClick() {
|
||||
this.setState({filteredValue: []});
|
||||
this.closeLayer();
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(localeable(HeadCellFilter));
|
102
src/components/table/HeadCellSort.tsx
Normal file
102
src/components/table/HeadCellSort.tsx
Normal file
@ -0,0 +1,102 @@
|
||||
/**
|
||||
* @file table/HeadCellSort
|
||||
* @author fex
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import {themeable, ThemeProps} from '../../theme';
|
||||
import {LocaleProps, localeable} from '../../locale';
|
||||
import {Icon} from '../icons';
|
||||
|
||||
export interface Props extends ThemeProps, LocaleProps {
|
||||
column: any;
|
||||
onSort?: Function;
|
||||
}
|
||||
|
||||
export interface State {
|
||||
order: string; // 升序还是降序
|
||||
orderBy: string; // 一次只能按一列排序 当前列的key
|
||||
}
|
||||
|
||||
export class HeadCellSort extends React.Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
order: '',
|
||||
orderBy: ''
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
column,
|
||||
onSort,
|
||||
classnames: cx
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<span
|
||||
className={cx('TableCell-sortBtn')}
|
||||
onClick={() => {
|
||||
const callback = () => {
|
||||
if (onSort) {
|
||||
onSort({
|
||||
orderBy: this.state.orderBy,
|
||||
order: this.state.order
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let sortPayload = {};
|
||||
if (column.key === this.state.orderBy) {
|
||||
if (this.state.order === 'descend') {
|
||||
// 降序改为取消
|
||||
sortPayload = {orderBy: '', order: 'ascend'};
|
||||
} else {
|
||||
// 升序之后降序
|
||||
sortPayload = {order: 'descend'};
|
||||
}
|
||||
} else {
|
||||
// 默认先升序
|
||||
sortPayload = {orderBy: column.key, order: 'ascend'};
|
||||
}
|
||||
|
||||
this.setState(sortPayload, callback);
|
||||
}}
|
||||
>
|
||||
<i
|
||||
className={cx(
|
||||
'TableCell-sortBtn--down',
|
||||
this.state.orderBy === column.key && this.state.order === 'descend'
|
||||
? 'is-active'
|
||||
: ''
|
||||
)}
|
||||
>
|
||||
<Icon icon="sort-desc" className="icon" />
|
||||
</i>
|
||||
<i
|
||||
className={cx(
|
||||
'TableCell-sortBtn--up',
|
||||
this.state.orderBy === column.key && this.state.order === 'ascend'
|
||||
? 'is-active'
|
||||
: ''
|
||||
)}
|
||||
>
|
||||
<Icon icon="sort-asc" className="icon" />
|
||||
</i>
|
||||
<i
|
||||
className={cx(
|
||||
'TableCell-sortBtn--default',
|
||||
this.state.orderBy === column.key ? '' : 'is-active'
|
||||
)}
|
||||
>
|
||||
<Icon icon="sort-default" className="icon" />
|
||||
</i>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default themeable(localeable(HeadCellSort));
|
1192
src/components/table/index.tsx
Normal file
1192
src/components/table/index.tsx
Normal file
File diff suppressed because it is too large
Load Diff
@ -178,6 +178,7 @@ import './renderers/Code';
|
||||
import './renderers/WebComponent';
|
||||
import './renderers/GridNav';
|
||||
import './renderers/TooltipWrapper';
|
||||
import './renderers/Table-v2';
|
||||
|
||||
import Scoped, {ScopedContext} from './Scoped';
|
||||
|
||||
|
@ -322,11 +322,14 @@ export const HocQuickEdit =
|
||||
);
|
||||
}
|
||||
|
||||
openQuickEdit() {
|
||||
openQuickEdit(e) {
|
||||
currentOpened = this;
|
||||
this.setState({
|
||||
isOpened: true
|
||||
});
|
||||
// QuickEdit在table中使用时,如果table配置了checkOnItemClick,会同时触发行选中
|
||||
// 所以这里阻止冒泡一下
|
||||
e.stopPropagation && e.stopPropagation();
|
||||
}
|
||||
|
||||
closeQuickEdit() {
|
||||
|
483
src/renderers/Table-v2/index.tsx
Normal file
483
src/renderers/Table-v2/index.tsx
Normal file
@ -0,0 +1,483 @@
|
||||
import React from 'react';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
|
||||
import {Renderer, RendererProps} from '../../factory';
|
||||
import {SchemaNode, Schema} from '../../types';
|
||||
import Table, {ColumnProps} from '../../components/table';
|
||||
import {
|
||||
BaseSchema,
|
||||
SchemaObject,
|
||||
SchemaTokenizeableString
|
||||
} from '../../Schema';
|
||||
import {isObject} from '../../utils/helper';
|
||||
import {
|
||||
resolveVariableAndFilter
|
||||
} from '../../utils/tpl-builtin';
|
||||
import {evalExpression, filter} from '../../utils/tpl';
|
||||
import {Icon} from '../../components/icons';
|
||||
import Checkbox from '../../components/Checkbox';
|
||||
import {TableStoreV2, ITableStore, IColumn} from '../../store/table-v2';
|
||||
import ColumnToggler from '../Table/ColumnToggler';
|
||||
|
||||
/**
|
||||
* Table 表格v2渲染器。
|
||||
* 文档:https://baidu.gitee.io/amis/docs/components/table-v2
|
||||
*/
|
||||
|
||||
export interface CellSpan {
|
||||
colIndex: number;
|
||||
rowIndex: number;
|
||||
colSpan?: number;
|
||||
rowSpan?: number;
|
||||
}
|
||||
|
||||
export interface RenderProps {
|
||||
colSpan?: number;
|
||||
rowSpan?: number;
|
||||
}
|
||||
|
||||
export interface ColumnSchema {
|
||||
/**
|
||||
* 指定列唯一标识
|
||||
*/
|
||||
key: string;
|
||||
|
||||
/**
|
||||
* 指定列标题
|
||||
*/
|
||||
title: string | SchemaObject;
|
||||
|
||||
/**
|
||||
* 指定列内容渲染器
|
||||
*/
|
||||
type?: string;
|
||||
|
||||
/**
|
||||
* 指定行合并表达式
|
||||
*/
|
||||
rowSpanExpr?: string;
|
||||
|
||||
/**
|
||||
* 指定列合并表达式
|
||||
*/
|
||||
colSpanExpr?: string;
|
||||
|
||||
/**
|
||||
* 表头分组
|
||||
*/
|
||||
children?: Array<ColumnSchema>
|
||||
}
|
||||
|
||||
export interface RowSelectionSchema {
|
||||
/**
|
||||
* 选择类型 单选/多选
|
||||
*/
|
||||
type: string;
|
||||
|
||||
/**
|
||||
* 对应数据源的key值
|
||||
*/
|
||||
keyField: string;
|
||||
|
||||
/**
|
||||
* 行是否禁用表达式
|
||||
*/
|
||||
disableOn: string;
|
||||
}
|
||||
|
||||
export interface ExpandableSchema {
|
||||
/**
|
||||
* 渲染器类型
|
||||
*/
|
||||
type: string;
|
||||
|
||||
/**
|
||||
* 对应数据源的key值
|
||||
*/
|
||||
keyField: string;
|
||||
|
||||
/**
|
||||
* 行是否可展开表达式
|
||||
*/
|
||||
expandableOn: string;
|
||||
|
||||
/**
|
||||
* 展开行自定义样式表达式
|
||||
*/
|
||||
expandedRowClassNameExpr: string;
|
||||
}
|
||||
|
||||
export interface TableSchema extends BaseSchema {
|
||||
/**
|
||||
* 指定为表格类型
|
||||
*/
|
||||
type: 'table-v2';
|
||||
|
||||
/**
|
||||
* 表格标题
|
||||
*/
|
||||
title: string | SchemaObject;
|
||||
|
||||
/**
|
||||
* 表格数据源
|
||||
*/
|
||||
source: SchemaTokenizeableString;
|
||||
|
||||
/**
|
||||
* 表格可自定义列
|
||||
*/
|
||||
columnsToggable: boolean;
|
||||
|
||||
/**
|
||||
* 表格列配置
|
||||
*/
|
||||
columns: Array<ColumnSchema>;
|
||||
|
||||
/**
|
||||
* 表格可选择配置
|
||||
*/
|
||||
rowSelection: RowSelectionSchema;
|
||||
|
||||
/**
|
||||
* 表格行可展开配置
|
||||
*/
|
||||
expandable: ExpandableSchema;
|
||||
}
|
||||
|
||||
export interface TableV2Props extends RendererProps {
|
||||
title?: string;
|
||||
source?: string;
|
||||
store: ITableStore;
|
||||
togglable: boolean;
|
||||
}
|
||||
|
||||
@Renderer({
|
||||
type: 'table-v2',
|
||||
storeType: TableStoreV2.name,
|
||||
name: 'table-v2'
|
||||
})
|
||||
export class TableRenderer extends React.Component<TableV2Props, object> {
|
||||
renderedToolbars: Array<string> = [];
|
||||
|
||||
constructor(props: TableV2Props) {
|
||||
super(props);
|
||||
|
||||
this.handleColumnToggle = this.handleColumnToggle.bind(this);
|
||||
|
||||
const {store, columnsToggable, columns} = props;
|
||||
|
||||
store.update({columnsToggable, columns});
|
||||
}
|
||||
|
||||
renderSchema(schema: any, props: any) {
|
||||
const {render} = this.props;
|
||||
// Table Header、Footer SchemaObject转化成ReactNode
|
||||
if (schema && isObject(schema)) {
|
||||
return render('field', schema, props);
|
||||
}
|
||||
return schema;
|
||||
}
|
||||
|
||||
getColumns(columns: Array<ColumnSchema>) {
|
||||
const cols: Array<ColumnProps> = [];
|
||||
const rowSpans: Array<CellSpan> = [];
|
||||
const colSpans: Array<CellSpan> = [];
|
||||
columns.forEach((column, col) => {
|
||||
const clone = {...column} as ColumnProps;
|
||||
if (isObject(column.title)) {
|
||||
const title = cloneDeep(column.title);
|
||||
Object.assign(clone, {
|
||||
title: () => this.renderSchema(title, {})
|
||||
});
|
||||
} else if (typeof column.title === 'string') {
|
||||
Object.assign(clone, {
|
||||
title: () => this.renderSchema({type: 'plain'}, {value: column.title})
|
||||
});
|
||||
}
|
||||
|
||||
if (column.type) {
|
||||
Object.assign(clone, {
|
||||
render: (text: string, record: any, rowIndex: number, colIndex: number) => {
|
||||
const props: RenderProps = {};
|
||||
const obj = {
|
||||
children: this.renderSchema(column, {
|
||||
data: record,
|
||||
value: record[column.key]
|
||||
}),
|
||||
props
|
||||
};
|
||||
if (column.rowSpanExpr) {
|
||||
const rowSpan = +filter(column.rowSpanExpr, {record, rowIndex, colIndex});
|
||||
if (rowSpan) {
|
||||
obj.props.rowSpan = rowSpan;
|
||||
rowSpans.push({colIndex, rowIndex, rowSpan})
|
||||
}
|
||||
}
|
||||
|
||||
if (column.colSpanExpr) {
|
||||
const colSpan = +filter(column.colSpanExpr, {record, rowIndex, colIndex});
|
||||
if (colSpan) {
|
||||
obj.props.colSpan = colSpan;
|
||||
colSpans.push({colIndex, rowIndex, colSpan});
|
||||
}
|
||||
}
|
||||
|
||||
rowSpans.forEach(item => {
|
||||
if (colIndex === item.colIndex
|
||||
&& rowIndex > item.rowIndex
|
||||
&& rowIndex < item.rowIndex + (item.rowSpan || 0)) {
|
||||
obj.props.rowSpan = 0;
|
||||
}
|
||||
});
|
||||
|
||||
colSpans.forEach(item => {
|
||||
if (rowIndex === item.rowIndex
|
||||
&& colIndex > item.colIndex
|
||||
&& colIndex < item.colIndex + (item.colSpan || 0)) {
|
||||
obj.props.colSpan = 0;
|
||||
}
|
||||
});
|
||||
|
||||
return obj;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (column.children) {
|
||||
clone.children = this.getColumns(column.children);
|
||||
}
|
||||
|
||||
cols.push(clone);
|
||||
});
|
||||
return cols;
|
||||
}
|
||||
|
||||
getSummary(summary: Array<any>) {
|
||||
const result: Array<any> = [];
|
||||
if (Array.isArray(summary)) {
|
||||
summary.forEach((s, index) => {
|
||||
if (isObject(s)) {
|
||||
result.push({
|
||||
colSpan: s.colSpan,
|
||||
fixed: s.fixed,
|
||||
render: () => this.renderSchema(s, {
|
||||
data: this.props.data
|
||||
})
|
||||
});
|
||||
} else if (Array.isArray(s)) {
|
||||
if (!result[index]) {
|
||||
result.push([]);
|
||||
}
|
||||
s.forEach(d => {
|
||||
result[index].push({
|
||||
colSpan: d.colSpan,
|
||||
fixed: d.fixed,
|
||||
render: () => this.renderSchema(s, {
|
||||
data: this.props.data
|
||||
})
|
||||
});
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return result.length ? result : null;
|
||||
}
|
||||
|
||||
handleColumnToggle(columns: Array<IColumn>) {
|
||||
const {store} = this.props;
|
||||
|
||||
store.update({columns});
|
||||
}
|
||||
|
||||
renderColumnsToggler(config?: any) {
|
||||
const {
|
||||
className,
|
||||
store,
|
||||
render,
|
||||
classPrefix: ns,
|
||||
classnames: cx,
|
||||
...rest
|
||||
} = this.props;
|
||||
const __ = rest.translate;
|
||||
const env = rest.env;
|
||||
|
||||
if (!store.toggable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<ColumnToggler
|
||||
{...rest}
|
||||
{...(isObject(config) ? config : {})}
|
||||
tooltip={config?.tooltip || __('Table.columnsVisibility')}
|
||||
tooltipContainer={
|
||||
env && env.getModalContainer ? env.getModalContainer : undefined
|
||||
}
|
||||
align={config?.align ?? 'left'}
|
||||
isActived={store.hasColumnHidden()}
|
||||
classnames={cx}
|
||||
classPrefix={ns}
|
||||
key="columns-toggable"
|
||||
size={config?.size || 'sm'}
|
||||
label={
|
||||
config?.label || <Icon icon="columns" className="icon m-r-none" />
|
||||
}
|
||||
draggable={config?.draggable}
|
||||
columns={store.columnsData}
|
||||
onColumnToggle={this.handleColumnToggle}
|
||||
>
|
||||
{store.toggableColumns.map(column => (
|
||||
<li
|
||||
className={cx('ColumnToggler-menuItem')}
|
||||
key={column.index}
|
||||
onClick={column.toggleToggle}
|
||||
>
|
||||
<Checkbox
|
||||
size="sm"
|
||||
classPrefix={ns}
|
||||
checked={column.toggled}>
|
||||
{column.title ? render('tpl', column.title) : null}
|
||||
</Checkbox>
|
||||
</li>
|
||||
))}
|
||||
</ColumnToggler>
|
||||
);
|
||||
}
|
||||
|
||||
renderToolbar(toolbar: SchemaNode) {
|
||||
const type = (toolbar as Schema).type || (toolbar as string);
|
||||
|
||||
if (type === 'columns-toggler') {
|
||||
this.renderedToolbars.push(type);
|
||||
return this.renderColumnsToggler(toolbar as any);
|
||||
}
|
||||
|
||||
return void 0;
|
||||
}
|
||||
|
||||
// handleAction() {}
|
||||
|
||||
renderActions(region: string) {
|
||||
let {actions, render, store, classnames: cx, data} = this.props;
|
||||
|
||||
actions = Array.isArray(actions) ? actions.concat() : [];
|
||||
|
||||
if (
|
||||
store.toggable &&
|
||||
region === 'header' &&
|
||||
!~this.renderedToolbars.indexOf('columns-toggler')
|
||||
) {
|
||||
actions.push({
|
||||
type: 'button',
|
||||
children: this.renderColumnsToggler()
|
||||
});
|
||||
}
|
||||
|
||||
return Array.isArray(actions) && actions.length ? (
|
||||
<div className={cx('Table-toolbar')}>
|
||||
{actions.map((action, key) =>
|
||||
render(
|
||||
`action/${key}`,
|
||||
{
|
||||
type: 'button',
|
||||
...(action as any)
|
||||
},
|
||||
{
|
||||
// onAction: this.handleAction,
|
||||
key
|
||||
// btnDisabled: store.dragging,
|
||||
// data: store.getData(data)
|
||||
}
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
) : null;
|
||||
}
|
||||
|
||||
renderTable() {
|
||||
const {
|
||||
render,
|
||||
title,
|
||||
footer,
|
||||
source,
|
||||
columns,
|
||||
rowSelection,
|
||||
expandable,
|
||||
footSummary,
|
||||
headSummary,
|
||||
classnames: cx,
|
||||
store,
|
||||
...rest
|
||||
} = this.props;
|
||||
|
||||
let sourceValue = this.props.data.items;
|
||||
|
||||
if (typeof source === 'string') {
|
||||
sourceValue = resolveVariableAndFilter(source, this.props.data, '| raw');
|
||||
}
|
||||
|
||||
if (expandable) {
|
||||
if (expandable.expandableOn) {
|
||||
const expandableOn = cloneDeep(expandable.expandableOn);
|
||||
expandable.rowExpandable = (record: any) => {
|
||||
return evalExpression(expandableOn, record);
|
||||
};
|
||||
delete expandable.expandableOn;
|
||||
}
|
||||
|
||||
if (expandable.type) {
|
||||
expandable.expandedRowRender = (record: any, rowIndex: number) => {
|
||||
return this.renderSchema(expandable, {data: record});
|
||||
};
|
||||
}
|
||||
|
||||
if (expandable.expandedRowClassNameExpr) {
|
||||
const expandedRowClassNameExpr = cloneDeep(expandable.expandedRowClassNameExpr);
|
||||
expandable.expandedRowClassName = (record: any, rowIndex: number) => {
|
||||
return filter(expandedRowClassNameExpr, {record, rowIndex});
|
||||
};
|
||||
delete expandable.expandedRowClassNameExpr;
|
||||
}
|
||||
}
|
||||
|
||||
if (rowSelection) {
|
||||
if (rowSelection.disableOn) {
|
||||
const disableOn = cloneDeep(rowSelection.disableOn);
|
||||
|
||||
rowSelection.getCheckboxProps = (record: any, rowIndex: number) => {
|
||||
return {
|
||||
disabled: evalExpression(disableOn, {record, rowIndex})
|
||||
};
|
||||
};
|
||||
|
||||
delete rowSelection.disableOn;
|
||||
}
|
||||
}
|
||||
|
||||
return <Table
|
||||
title={this.renderSchema(title, {data: this.props.data})}
|
||||
footer={this.renderSchema(footer, {data: this.props.data})}
|
||||
columns={this.getColumns(store.filteredColumns)}
|
||||
dataSource={sourceValue}
|
||||
rowSelection={rowSelection}
|
||||
expandable={expandable}
|
||||
footSummary={this.getSummary(footSummary)}
|
||||
headSummary={this.getSummary(headSummary)}
|
||||
{...rest}>
|
||||
</Table>;
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
classnames: cx
|
||||
} = this.props;
|
||||
|
||||
this.renderedToolbars = []; // 用来记录哪些 toolbar 已经渲染了
|
||||
|
||||
return <div className={cx('Table-wrapper')}>
|
||||
{this.renderActions('header')}
|
||||
{this.renderTable()}
|
||||
</div>;
|
||||
}
|
||||
}
|
@ -156,14 +156,16 @@ export class TableBody extends React.Component<TableBodyProps> {
|
||||
classnames: cx,
|
||||
rows,
|
||||
prefixRowClassName,
|
||||
affixRowClassName
|
||||
affixRowClassName,
|
||||
footable
|
||||
} = this.props;
|
||||
|
||||
if (!(Array.isArray(items) && items.length)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const filterColumns = columns.filter(item => item.toggable);
|
||||
// 开启了footable,不需要考虑设置了breakpoint的列了
|
||||
const filterColumns = columns.filter(item => item.toggable && !(footable && item.breakpoint));
|
||||
const result: any[] = [];
|
||||
|
||||
for (let index = 0; index < filterColumns.length; index++) {
|
||||
@ -182,14 +184,16 @@ export class TableBody extends React.Component<TableBodyProps> {
|
||||
}
|
||||
|
||||
// 缺少的单元格补齐
|
||||
// 考虑是否设置了
|
||||
// 开启了footable,不需要考虑设置了breakpoint的列了
|
||||
const appendLen =
|
||||
columns.length - result.reduce((p, c) => p + (c.colSpan || 1), 0);
|
||||
(footable ? columns.filter(item => !item.breakpoint).length : columns.length) - result.reduce((p, c) => p + (c.colSpan || 1), 0);
|
||||
|
||||
if (appendLen) {
|
||||
const item = result.pop();
|
||||
result.push({
|
||||
...item,
|
||||
colSpan: (item.colSpan || 1) + appendLen
|
||||
colSpan: (item?.colSpan || 1) + appendLen
|
||||
});
|
||||
}
|
||||
const ctx = createObject(data, {
|
||||
|
@ -12,6 +12,7 @@ import {ComboStore} from './combo';
|
||||
import {FormStore} from './form';
|
||||
import {CRUDStore} from './crud';
|
||||
import {TableStore} from './table';
|
||||
import {TableStoreV2} from './table-v2';
|
||||
import {ListStore} from './list';
|
||||
import {ModalStore} from './modal';
|
||||
import {TranslateFn} from '../locale';
|
||||
@ -33,6 +34,7 @@ const allowedStoreList = [
|
||||
ComboStore,
|
||||
CRUDStore,
|
||||
TableStore,
|
||||
TableStoreV2,
|
||||
ListStore,
|
||||
ModalStore,
|
||||
FormItemStore,
|
||||
|
185
src/store/table-v2.ts
Normal file
185
src/store/table-v2.ts
Normal file
@ -0,0 +1,185 @@
|
||||
import {
|
||||
types,
|
||||
getParent,
|
||||
Instance,
|
||||
SnapshotIn,
|
||||
isAlive
|
||||
} from 'mobx-state-tree';
|
||||
|
||||
import {isVisible, hasVisibleExpression} from '../utils/helper';
|
||||
import {iRendererStore} from './iRenderer';
|
||||
|
||||
export const Column = types
|
||||
.model('Column', {
|
||||
title: types.optional(types.frozen(), undefined),
|
||||
key: '',
|
||||
toggled: false,
|
||||
breakpoint: types.optional(types.frozen(), undefined),
|
||||
pristine: types.optional(types.frozen(), undefined),
|
||||
toggable: true,
|
||||
index: 0,
|
||||
type: ''
|
||||
})
|
||||
.actions(self => ({
|
||||
toggleToggle() {
|
||||
self.toggled = !self.toggled;
|
||||
const table = getParent(self, 2) as ITableStore;
|
||||
|
||||
if (!table.activeToggaleColumns.length) {
|
||||
self.toggled = true;
|
||||
}
|
||||
|
||||
table.persistSaveToggledColumns();
|
||||
},
|
||||
setToggled(value: boolean) {
|
||||
self.toggled = value;
|
||||
}
|
||||
}));
|
||||
|
||||
export type IColumn = Instance<typeof Column>;
|
||||
export type SColumn = SnapshotIn<typeof Column>;
|
||||
|
||||
export const Row = types
|
||||
.model('Row', {
|
||||
data: types.frozen({} as any)
|
||||
});
|
||||
|
||||
export type IRow = Instance<typeof Row>;
|
||||
export type SRow = SnapshotIn<typeof Row>;
|
||||
|
||||
export const TableStoreV2 = iRendererStore
|
||||
.named('TableStoreV2')
|
||||
.props({
|
||||
columns: types.array(Column),
|
||||
rows: types.array(Row),
|
||||
columnsToggable: types.optional(
|
||||
types.union(types.boolean, types.literal('auto')),
|
||||
'auto'
|
||||
)
|
||||
})
|
||||
.views(self => {
|
||||
function getToggable() {
|
||||
if (self.columnsToggable === 'auto') {
|
||||
return self.columns.filter.length > 10;
|
||||
}
|
||||
|
||||
return self.columnsToggable;
|
||||
}
|
||||
|
||||
function hasColumnHidden() {
|
||||
return self.columns.findIndex(column => !column.toggled) !== -1;
|
||||
}
|
||||
|
||||
function getToggableColumns() {
|
||||
return self.columns.filter(
|
||||
item => isVisible(item.pristine, self.data) && item.toggable !== false
|
||||
);
|
||||
}
|
||||
|
||||
function getActiveToggableColumns() {
|
||||
return getToggableColumns().filter(item => item.toggled);
|
||||
}
|
||||
|
||||
function getFilteredColumns() {
|
||||
return self.columns.filter(
|
||||
item =>
|
||||
item &&
|
||||
isVisible(
|
||||
item.pristine,
|
||||
hasVisibleExpression(item.pristine) ? self.data : {}
|
||||
) &&
|
||||
(item.toggled || !item.toggable)
|
||||
).map(item => ({...item.pristine, type: item.type}));
|
||||
}
|
||||
|
||||
return {
|
||||
get toggable() {
|
||||
return getToggable();
|
||||
},
|
||||
|
||||
get columnsData() {
|
||||
return self.columns;
|
||||
},
|
||||
|
||||
get toggableColumns() {
|
||||
return getToggableColumns();
|
||||
},
|
||||
|
||||
get filteredColumns() {
|
||||
return getFilteredColumns();
|
||||
},
|
||||
|
||||
get activeToggaleColumns() {
|
||||
return getActiveToggableColumns();
|
||||
},
|
||||
|
||||
// 是否隐藏了某列
|
||||
hasColumnHidden() {
|
||||
return hasColumnHidden();
|
||||
}
|
||||
}
|
||||
})
|
||||
.actions(self => {
|
||||
function update(config: Partial<STableStore>) {
|
||||
config.columnsToggable !== void 0 &&
|
||||
(self.columnsToggable = config.columnsToggable);
|
||||
|
||||
if (config.columns && Array.isArray(config.columns)) {
|
||||
let columns: Array<SColumn> = config.columns
|
||||
.filter(column => column)
|
||||
.concat();
|
||||
|
||||
columns = columns.map((item, index) => ({
|
||||
...item,
|
||||
index,
|
||||
type: item.type || 'plain',
|
||||
pristine: item,
|
||||
toggled: item.toggled !== false,
|
||||
breakpoint: item.breakpoint
|
||||
}));
|
||||
|
||||
self.columns.replace(columns as any);
|
||||
}
|
||||
}
|
||||
|
||||
function persistSaveToggledColumns() {
|
||||
const key =
|
||||
location.pathname +
|
||||
self.path +
|
||||
self.toggableColumns.map(item => item.key || item.index).join('-');
|
||||
localStorage.setItem(
|
||||
key,
|
||||
JSON.stringify(self.activeToggaleColumns.map(item => item.index))
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
update,
|
||||
persistSaveToggledColumns,
|
||||
|
||||
// events
|
||||
afterCreate() {
|
||||
setTimeout(() => {
|
||||
if (!isAlive(self)) {
|
||||
return;
|
||||
}
|
||||
const key =
|
||||
location.pathname +
|
||||
self.path +
|
||||
self.toggableColumns.map(item => item.key || item.index).join('-');
|
||||
|
||||
const data = localStorage.getItem(key);
|
||||
|
||||
if (data) {
|
||||
const selectedColumns = JSON.parse(data);
|
||||
self.toggableColumns.forEach(item =>
|
||||
item.setToggled(!!~selectedColumns.indexOf(item.index))
|
||||
);
|
||||
}
|
||||
}, 200);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
export type ITableStore = Instance<typeof TableStoreV2>;
|
||||
export type STableStore = SnapshotIn<typeof TableStoreV2>;
|
@ -639,7 +639,8 @@ export const TableStore = iRendererStore
|
||||
},
|
||||
|
||||
get disabledHeadCheckbox() {
|
||||
const selectedLength = self.data?.selectedItems.length;
|
||||
// 设置为multiple 默认没选择会报错
|
||||
const selectedLength = self.data?.selectedItems?.length;
|
||||
const maxLength = self.maxKeepItemSelectionLength;
|
||||
|
||||
if (!self.data || !self.keepItemSelectionOnPageChange || !maxLength) {
|
||||
|
Loading…
Reference in New Issue
Block a user