Merge branch 'master' into feat-formulaeditor

This commit is contained in:
hsm-lv 2023-06-16 17:31:18 +08:00 committed by GitHub
commit 78a81e3d0e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
235 changed files with 1779 additions and 593 deletions

View File

@ -2269,6 +2269,61 @@ crud 组件支持通过配置`headerToolbar`和`footerToolbar`属性,实现在
}
```
还可以定制文案和按钮如:
```schema: scope="body"
{
"type": "crud",
"syncLocation": false,
"api": "/api/mock2/sample",
"filter": {
"title": "条件搜索",
"body": [
{
"type": "input-text",
"name": "keywords",
"placeholder": "通过关键字搜索"
}
]
},
"filterTogglable": {
"label": "更多搜索",
"activeLabel": "收起搜索",
"icon": "fa fa-arrow-down mr-1",
"activeIcon": "fa fa-arrow-up mr-1"
},
"headerToolbar": [
"filter-toggler"
],
"columns": [
{
"name": "id",
"label": "ID"
},
{
"name": "engine",
"label": "Rendering engine"
},
{
"name": "browser",
"label": "Browser"
},
{
"name": "platform",
"label": "Platform(s)"
},
{
"name": "version",
"label": "Engine version"
},
{
"name": "grade",
"label": "CSS grade"
}
]
}
```
### 刷新按钮
> 1.5.0 及以上版本
@ -2862,60 +2917,60 @@ itemAction 里的 onClick 还能通过 `data` 参数拿到当前行的数据,
## 属性表
| 属性名 | 类型 | 默认值 | 说明 |
| ------------------------------------- | ------------------------------- | ------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| type | `string` | | `type` 指定为 CRUD 渲染器 |
| mode | `string` | `"table"` | `"table" 、 "cards" 或者 "list"` |
| title | `string` | `""` | 可设置成空,当设置成空时,没有标题栏 |
| className | `string` | | 表格外层 Dom 的类名 |
| api | [API](../../docs/types/api) | | CRUD 用来获取列表数据的 api。 |
| loadDataOnce | `boolean` | | 是否一次性加载所有数据(前端分页) |
| loadDataOnceFetchOnFilter | `boolean` | `true` | 在开启 loadDataOnce 时filter 时是否去重新请求 api |
| source | `string` | | 数据映射接口返回某字段的值,不设置会默认使用接口返回的`${items}`或者`${rows}`,也可以设置成上层数据源的内容 |
| filter | [Form](./form/index) | | 设置过滤器,当该表单提交后,会把数据带给当前 `mode` 刷新列表。 |
| filterTogglable | `boolean` | `false` | 是否可显隐过滤器 |
| filterDefaultVisible | `boolean` | `true` | 设置过滤器默认是否可见。 |
| initFetch | `boolean` | `true` | 是否初始化的时候拉取数据, 只针对有 filter 的情况, 没有 filter 初始都会拉取数据 |
| interval | `number` | `3000` | 刷新时间(最低 1000) |
| silentPolling | `boolean` | `false` | 配置刷新时是否隐藏加载动画 |
| stopAutoRefreshWhen | `string` | `""` | 通过[表达式](../../docs/concepts/expression)来配置停止刷新的条件 |
| stopAutoRefreshWhenModalIsOpen | `boolean` | `false` | 当有弹框时关闭自动刷新,关闭弹框又恢复 |
| syncLocation | `boolean` | `true` | 是否将过滤条件的参数同步到地址栏 |
| draggable | `boolean` | `false` | 是否可通过拖拽排序 |
| resizable | `boolean` | `true` | 是否可以调整列宽度 |
| itemDraggableOn | `boolean` | | 用[表达式](../../docs/concepts/expression)来配置是否可拖拽排序 |
| [saveOrderApi](#saveOrderApi) | [API](../../docs/types/api) | | 保存排序的 api。 |
| [quickSaveApi](#quickSaveApi) | [API](../../docs/types/api) | | 快速编辑后用来批量保存的 API。 |
| [quickSaveItemApi](#quickSaveItemApi) | [API](../../docs/types/api) | | 快速编辑配置成及时保存时使用的 API。 |
| bulkActions | Array<[Action](./action)> | | 批量操作列表,配置后,表格可进行选中操作。 |
| messages | `Object` | | 覆盖消息提示,如果不指定,将采用 api 返回的 message |
| messages.fetchFailed | `string` | | 获取失败时提示 |
| messages.saveOrderFailed | `string` | | 保存顺序失败提示 |
| messages.saveOrderSuccess | `string` | | 保存顺序成功提示 |
| messages.quickSaveFailed | `string` | | 快速保存失败提示 |
| messages.quickSaveSuccess | `string` | | 快速保存成功提示 |
| primaryField | `string` | `"id"` | 设置 ID 字段名。 |
| perPage | `number` | 10 | 设置一页显示多少条数据。 |
| orderBy | `string` | | 默认排序字段,这个是传给后端,需要后端接口实现 |
| orderDir | `asc` \| `desc` | | 排序方向 |
| defaultParams | `Object` | | 设置默认 filter 默认参数,会在查询的时候一起发给后端 |
| pageField | `string` | `"page"` | 设置分页页码字段名。 |
| perPageField | `string` | `"perPage"` | 设置分页一页显示的多少条数据的字段名。注意:最好与 defaultParams 一起使用,请看下面例子。 |
| perPageAvailable | `Array<number>` | `[5, 10, 20, 50, 100]` | 设置一页显示多少条数据下拉框可选条数。 |
| orderField | `string` | | 设置用来确定位置的字段名,设置后新的顺序将被赋值到该字段中。 |
| hideQuickSaveBtn | `boolean` | `false` | 隐藏顶部快速保存提示 |
| autoJumpToTopOnPagerChange | `boolean` | `false` | 当切分页的时候,是否自动跳顶部。 |
| syncResponse2Query | `boolean` | `true` | 将返回数据同步到过滤器上。 |
| keepItemSelectionOnPageChange | `boolean` | `true` | 保留条目选择,默认分页、搜素后,用户选择条目会被清空,开启此选项后会保留用户选择,可以实现跨页面批量操作。 |
| labelTpl | `string` | | 单条描述模板,`keepItemSelectionOnPageChange`设置为`true`后会把所有已选择条目列出来,此选项可以用来定制条目展示文案。 |
| headerToolbar | Array | `['bulkActions', 'pagination']` | 顶部工具栏配置 |
| footerToolbar | Array | `['statistics', 'pagination']` | 底部工具栏配置 |
| alwaysShowPagination | `boolean` | `false` | 是否总是显示分页 |
| affixHeader | `boolean` | `true` | 是否固定表头(table 下) |
| autoGenerateFilter | `Object \| boolean` | | 是否开启查询区域,开启后会根据列元素的 `searchable` 属性值,自动生成查询条件表单 |
| resetPageAfterAjaxItemAction | `boolean` | `false` | 单条数据 ajax 操作后是否重置页码为第一页 |
| autoFillHeight | `boolean``{height: number}` | | 内容区域自适应高度 |
| canAccessSuperData | `boolean` | `true` | 指定是否可以自动获取上层的数据并映射到表格行数据上,如果列也配置了该属性,则列的优先级更高 |
| 属性名 | 类型 | 默认值 | 说明 |
| ------------------------------------- | --------------------------------------------------------------------------------------- | ------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| type | `string` | | `type` 指定为 CRUD 渲染器 |
| mode | `string` | `"table"` | `"table" 、 "cards" 或者 "list"` |
| title | `string` | `""` | 可设置成空,当设置成空时,没有标题栏 |
| className | `string` | | 表格外层 Dom 的类名 |
| api | [API](../../docs/types/api) | | CRUD 用来获取列表数据的 api。 |
| loadDataOnce | `boolean` | | 是否一次性加载所有数据(前端分页) |
| loadDataOnceFetchOnFilter | `boolean` | `true` | 在开启 loadDataOnce 时filter 时是否去重新请求 api |
| source | `string` | | 数据映射接口返回某字段的值,不设置会默认使用接口返回的`${items}`或者`${rows}`,也可以设置成上层数据源的内容 |
| filter | [Form](./form/index) | | 设置过滤器,当该表单提交后,会把数据带给当前 `mode` 刷新列表。 |
| filterTogglable | `boolean` \| `{label: string; icon: string; activeLabel: string; activeIcon?: stirng;}` | `false` | 是否可显隐过滤器 |
| filterDefaultVisible | `boolean` | `true` | 设置过滤器默认是否可见。 |
| initFetch | `boolean` | `true` | 是否初始化的时候拉取数据, 只针对有 filter 的情况, 没有 filter 初始都会拉取数据 |
| interval | `number` | `3000` | 刷新时间(最低 1000) |
| silentPolling | `boolean` | `false` | 配置刷新时是否隐藏加载动画 |
| stopAutoRefreshWhen | `string` | `""` | 通过[表达式](../../docs/concepts/expression)来配置停止刷新的条件 |
| stopAutoRefreshWhenModalIsOpen | `boolean` | `false` | 当有弹框时关闭自动刷新,关闭弹框又恢复 |
| syncLocation | `boolean` | `true` | 是否将过滤条件的参数同步到地址栏 |
| draggable | `boolean` | `false` | 是否可通过拖拽排序 |
| resizable | `boolean` | `true` | 是否可以调整列宽度 |
| itemDraggableOn | `boolean` | | 用[表达式](../../docs/concepts/expression)来配置是否可拖拽排序 |
| [saveOrderApi](#saveOrderApi) | [API](../../docs/types/api) | | 保存排序的 api。 |
| [quickSaveApi](#quickSaveApi) | [API](../../docs/types/api) | | 快速编辑后用来批量保存的 API。 |
| [quickSaveItemApi](#quickSaveItemApi) | [API](../../docs/types/api) | | 快速编辑配置成及时保存时使用的 API。 |
| bulkActions | Array<[Action](./action)> | | 批量操作列表,配置后,表格可进行选中操作。 |
| messages | `Object` | | 覆盖消息提示,如果不指定,将采用 api 返回的 message |
| messages.fetchFailed | `string` | | 获取失败时提示 |
| messages.saveOrderFailed | `string` | | 保存顺序失败提示 |
| messages.saveOrderSuccess | `string` | | 保存顺序成功提示 |
| messages.quickSaveFailed | `string` | | 快速保存失败提示 |
| messages.quickSaveSuccess | `string` | | 快速保存成功提示 |
| primaryField | `string` | `"id"` | 设置 ID 字段名。 |
| perPage | `number` | 10 | 设置一页显示多少条数据。 |
| orderBy | `string` | | 默认排序字段,这个是传给后端,需要后端接口实现 |
| orderDir | `asc` \| `desc` | | 排序方向 |
| defaultParams | `Object` | | 设置默认 filter 默认参数,会在查询的时候一起发给后端 |
| pageField | `string` | `"page"` | 设置分页页码字段名。 |
| perPageField | `string` | `"perPage"` | 设置分页一页显示的多少条数据的字段名。注意:最好与 defaultParams 一起使用,请看下面例子。 |
| perPageAvailable | `Array<number>` | `[5, 10, 20, 50, 100]` | 设置一页显示多少条数据下拉框可选条数。 |
| orderField | `string` | | 设置用来确定位置的字段名,设置后新的顺序将被赋值到该字段中。 |
| hideQuickSaveBtn | `boolean` | `false` | 隐藏顶部快速保存提示 |
| autoJumpToTopOnPagerChange | `boolean` | `false` | 当切分页的时候,是否自动跳顶部。 |
| syncResponse2Query | `boolean` | `true` | 将返回数据同步到过滤器上。 |
| keepItemSelectionOnPageChange | `boolean` | `true` | 保留条目选择,默认分页、搜素后,用户选择条目会被清空,开启此选项后会保留用户选择,可以实现跨页面批量操作。 |
| labelTpl | `string` | | 单条描述模板,`keepItemSelectionOnPageChange`设置为`true`后会把所有已选择条目列出来,此选项可以用来定制条目展示文案。 |
| headerToolbar | Array | `['bulkActions', 'pagination']` | 顶部工具栏配置 |
| footerToolbar | Array | `['statistics', 'pagination']` | 底部工具栏配置 |
| alwaysShowPagination | `boolean` | `false` | 是否总是显示分页 |
| affixHeader | `boolean` | `true` | 是否固定表头(table 下) |
| autoGenerateFilter | `Object \| boolean` | | 是否开启查询区域,开启后会根据列元素的 `searchable` 属性值,自动生成查询条件表单 |
| resetPageAfterAjaxItemAction | `boolean` | `false` | 单条数据 ajax 操作后是否重置页码为第一页 |
| autoFillHeight | `boolean``{height: number}` | | 内容区域自适应高度 |
| canAccessSuperData | `boolean` | `true` | 指定是否可以自动获取上层的数据并映射到表格行数据上,如果列也配置了该属性,则列的优先级更高 |
注意除了上面这些属性CRUD 在不同模式下的属性需要参考各自的文档,比如

View File

@ -490,7 +490,7 @@ type Value = ValueGroup;
"label": "条件组件",
"name": "conditions",
"description": "适合让用户自己拼查询条件,然后后端根据数据生成 query where",
"source": "/api/condition-fields?a=${a}&waitSeconds=2"
"source": "/api/condition-fields/custom?a=${a}&waitSeconds=2"
}
]
}
@ -500,7 +500,7 @@ type Value = ValueGroup;
> 2.3.0 及以上版本
通过 selectMode 配置组合条件左侧选项类型,可配置项为`list`、`tree`,默认为`list`。两者数据格式相同,只是下拉框展示方式不同,当存在多层 children 嵌套时,建议使用`tree`。
通过 selectMode 配置组合条件左侧选项类型,可配置项为`list`、`tree`、`chained`,默认为`list`。这三个数据格式基本类似,只是下拉框展示方式不同,`tree`是树形下拉,`chained`为多个级联的下拉。当存在多层 children 嵌套时,建议使用`tree`。
selectMode 为`list`时
@ -640,6 +640,84 @@ selectMode 为`tree`时
}
```
> 3.2.0 及以上版本
selectMode 为`chained`时,使用`fields`字段
```schema: scope="body"
{
"type": "form",
"debug": true,
"body": [
{
"type": "condition-builder",
"label": "条件组件",
"name": "conditions",
"selectMode": "chained",
"description": "适合让用户自己拼查询条件,然后后端根据数据生成 query where",
"fields": [
{
"label": "文本",
"type": "text",
"name": "text"
},
{
"label": "数字",
"type": "number",
"name": "number"
},
{
"label": "布尔",
"type": "boolean",
"name": "boolean"
},
{
"label": "链式结构",
"name": "chained",
"children": [
{
"label": "Folder A",
"name": "Folder_A",
"children": [
{
"label": "file A",
"name": "file_A",
"type": "number"
},
{
"label": "file B",
"name": "file_B",
"type": "text"
}
]
}
]
}
]
}
]
}
```
selectMode 为`chained`时,使用`source`字段
```schema: scope="body"
{
"type": "form",
"debug": true,
"body": [
{
"type": "condition-builder",
"label": "条件组件",
"name": "conditions",
"selectMode": "chained",
"description": "适合让用户自己拼查询条件,然后后端根据数据生成 query where",
"source": "/api/condition-fields/chained"
}
]
}
```
## 简易模式
通过 builderMode 配置为简易模式,在这个模式下将不开启树形分组功能,输出结果只有一层,方便后端实现简单的 SQL 生成。
@ -918,7 +996,7 @@ selectMode 为`tree`时
## 属性表
| 属性名 | 类型 | 默认值 | 说明 |
| 属性名 | 类型 | 默认值 | 说明 |
| -------------- | ------------------ | -------- | ------------------------------ |
| className | `string` | | 外层 dom 类名 |
| fieldClassName | `string` | | 输入字段的类名 |
@ -929,4 +1007,6 @@ selectMode 为`tree`时
| showANDOR | `boolean` | | 用于 simple 模式下显示切换按钮 |
| showNot | `boolean` | | 是否显示「非」按钮 |
| searchable | `boolean` | | 字段是否可搜索 |
| selectMode | `'list'`、`'tree'` | `'list'` | 组合条件左侧选项类型 |
| selectMode | `'list'` \| `'tree'` \| `'chained'` | `'list'` | 组合条件左侧选项类型。`'chained'`模式需要`3.2.0及以上版本` |
| addBtnVisibleOn | `string` | | 表达式:控制按钮“添加条件”的显示。参数为`depth`、`breadth`,分别代表深度、长度。表达式需要返回`boolean`类型`3.2.0及以上版本` |
| addGroupBtnVisibleOn | `string` | | 表达式:控制按钮“添加条件组”的显示。参数为`depth`、`breadth`,分别代表深度、长度。表达式需要返回`boolean`类型`3.2.0及以上版本` |

View File

@ -530,6 +530,46 @@ order: 68
}
```
内容来源于 source
```schema: scope="body"
{
"type": "page",
"data": {
"arr": [
{
"a": "收入",
"b": 199,
"key": "a"
},
{
"a": "支出",
"b": 299,
"key": "b"
}
]
},
"body": [
{
"type": "tabs",
"activeKey": "b",
"source": "${arr}",
"tabs": [
{
"title": "${a}",
"hash": "${key}",
"body": {
"type": "tpl",
"tpl": "金额:${b|number}元"
}
}
]
}
]
}
```
#### 配置索引值
单个`tab`上不要配置`hash`属性,配置需要展示的`tab`索引值,`0`代表第一个。支持变量,如`"${id}"`

View File

@ -192,9 +192,31 @@ page
> **注意:** 当前例子中,对数据域中数据的获取使用的是 **\${xxx}** 模板语法,但是在不同的组件配置项中,获取数据的语法会有差异,我们会在后续的[模板](./template)和[表达式章节](./expression)中一一介绍。
### 具备数据域的组件
- App
- Page
- Cards
- Chart
- CRUD
- CRUD2
- Dialog
- Drawer
- List
- Page
- PaginationWrapper
- Service
- Wizard
- Combo
- InputArray
- Table
- Table2
有个特殊情况是 CRUD 中 filter实际上是个 form所以 CRUD 中有两层数据域,第一层是 CRUD 本身,同时查询条件表单中也有一层数据域。
### 常见误解
需要注意,只有少数几个容器组件会创建新的数据域,除了最顶层的 Page还有 CRUD、Dialog、IFrame、Form、Service 等。
需要注意,只有少数几个容器组件会创建新的数据域,具体查看[具备数据域的组件](#具备数据域的组件)列表
常见的错误写法是给容器组件加 data 属性,比如:
@ -377,6 +399,53 @@ page
> 具有类似特征的组件还有`Formula`等
## 更新数据链
通常顶层数据域数据更新,孩子中具备数据域的组件都会更新,如果不更新会拿不到最新的值。从功能来看这个更新代价其实是很大的,有性能损耗,比如如果我在顶层更新了个变量 `name`,所有的孩子都会重新刷新一遍。
目前 amis 中,具备数据域的组件,默认会检测两层节点的数据是否发生变化(上层数据域和上上层数据域),来决定当前层的数据要不要更新。存在两个问题:
1. 当前组件也许并不关心上层数据是否变化,没必要进行这些刷新操作
2. 当前组件关系上上层的数据变化,但是在此拿不到最新的。(比如:放在 service 中的 crudcrud 中 filter 用了 service 的接口返回数据,但是拿不到最新的)
amis 从 3.2.0 版本开始针对[具备数据域的组件](#具备数据域的组件)新增了 `trackExpression` 属性,用来主动配置当前组件需要关心的上层数据。
针对以上问题,则可以通过这样配置来解决
1. `trackExpression` 配置成 `"none"` 也就是说不追踪任何数据。
2. `trackExpression` 配置成 `"${xxxVariable}"` 这样 xxxVariable 变化了更新当前组件的数据链。
关于 `trackExpression` 的语法,请查看表达式篇章,可以监听多个变量比如: `"${xxx1},${xxx2}"`,还可以写表单时如 `"${ xxx ? xxx : yyy}"`
amis 内部是通过运算这个表达式的结果来判断。所以表达式中千万不要用随机函数,或者用当前时间等,否则每次都会更新数据链。另外如果变量是数组,或者对象,会转成统一的字符串 `[object Array]` 或者 `[object Object]` 这个其实会影响检测的,所以建议转成 json 字符串如。 `${xxxObject | json}`。还有就是既然是监控上层数据,表达式中不要写当前层数据变量,是取不到的。
```schema
{
"data": {
"name": "amis"
},
"type": "page",
"body": [
{ "label": "请修改输入框", "type": "input-text", "name": "name"},
{
"type": "switch",
"label": "同步更新",
"name": "syncSwitch"
},
{
"type": "crud",
"filter": {
"trackExpression": "${syncSwitch ? name : ''}",
"body": [
"my name is ${name}"
]
}
}
]
}
```
## URL 参数
url 中的参数会进入顶层数据域,比如下面的例子,可以点击[这里](./datascope-and-datachain?word=myquery#url-参数)看效果。

View File

@ -236,6 +236,34 @@ amisScoped.updateProps(
);
```
### 更新配置
可以通过 amisScoped 对象的 udpateSchema 方法来更新更新内容配置。
```js
let amisJSON = {
type: 'page',
body: [
'inital string',
{
type: 'button',
label: 'Change',
onClick: handleChange
}
]
};
let amisScoped = amis.embed('#root', amisJSON);
function handleChange() {
const schema = {
...amisJSON,
body: ['changed']
};
amisScoped.updateSchema(schema);
}
```
### 多页模式
默认 amis 渲染是单页模式,如果想实现多页应用,请使用 [app 渲染器](../../components/app)。

View File

@ -295,6 +295,10 @@ export function embed(
updateProps: (props: any, callback?: () => void) => {
root.render(createElements(props));
},
updateSchema: (newSchema: any, props = {}) => {
schema = newSchema;
root.render(createElements(props));
},
unmount: () => {
root.unmount();
}

View File

@ -18,10 +18,3 @@ import 'core-js/es/symbol';
import './cloest';
// @ts-ignore
import './classList';
// ios 没有这个会报错
if (!('DragEvent' in window)) {
Object.defineProperty(window, 'DragEvent', {
value: class DragEvent {}
});
}

View File

@ -0,0 +1,44 @@
{
"status": 0,
"msg": "",
"data": {
"fields": [
{
"label": "文本",
"type": "text",
"name": "text"
},
{
"label": "数字",
"type": "number",
"name": "number"
},
{
"label": "布尔",
"type": "boolean",
"name": "boolean"
},
{
"label": "日期",
"name": "date",
"children": [
{
"label": "日期1",
"type": "date",
"name": "date1"
},
{
"label": "时间2",
"type": "time",
"name": "time2"
},
{
"label": "日期时间3",
"type": "datetime",
"name": "datetime"
}
]
}
]
}
}

View File

@ -60,7 +60,8 @@ export const RENDERER_TRANSMISSION_OMIT_PROPS = [
'id',
'inputOnly',
'label',
'renderLabel'
'renderLabel',
'trackExpression'
];
const componentCache: SimpleMap = new SimpleMap();

View File

@ -15,7 +15,7 @@ import {
syncDataFromSuper,
isSuperDataModified
} from './utils/helper';
import {dataMapping} from './utils/tpl-builtin';
import {dataMapping, tokenize} from './utils/tpl-builtin';
import {RootStoreContext} from './WithRootStore';
export function HocStoreFactory(renderer: {
@ -191,13 +191,16 @@ export function HocStoreFactory(renderer: {
if (
shouldSync === true ||
prevProps.defaultData !== props.defaultData ||
isObjectShallowModified(prevProps.data, props.data) ||
//
// 特殊处理 CRUD。
// CRUD 中 toolbar 里面的 data 是空对象,但是 __super 会不一样
(props.data &&
prevProps.data &&
props.data.__super !== prevProps.data.__super)
(props.trackExpression
? tokenize(props.trackExpression, props.data!) !==
tokenize(props.trackExpression, prevProps.data!)
: isObjectShallowModified(prevProps.data, props.data) ||
//
// 特殊处理 CRUD。
// CRUD 中 toolbar 里面的 data 是空对象,但是 __super 会不一样
(props.data &&
prevProps.data &&
props.data.__super !== prevProps.data.__super))
) {
store.initData(
extendObject(props.data, {
@ -209,9 +212,12 @@ export function HocStoreFactory(renderer: {
}
} else if (
shouldSync === true ||
isObjectShallowModified(prevProps.data, props.data) ||
(props.syncSuperStore !== false &&
isSuperDataModified(props.data, prevProps.data, store))
(props.trackExpression
? tokenize(props.trackExpression, props.data!) !==
tokenize(props.trackExpression, prevProps.data!)
: isObjectShallowModified(prevProps.data, props.data) ||
(props.syncSuperStore !== false &&
isSuperDataModified(props.data, prevProps.data, store)))
) {
if (props.store && props.store.data === props.data) {
store.initData(
@ -246,9 +252,8 @@ export function HocStoreFactory(renderer: {
store.initData(createObject(props.scope, props.data));
}
} else if (
(shouldSync === true ||
!props.store ||
props.data !== props.store.data) &&
!props.trackExpression &&
(!props.store || props.data !== props.store.data) &&
props.data &&
props.data.__super
) {
@ -273,9 +278,10 @@ export function HocStoreFactory(renderer: {
}
// nextProps.data.__super !== props.data.__super) &&
} else if (
!props.trackExpression &&
props.scope &&
props.data === props.store!.data &&
(shouldSync === true || prevProps.data !== props.data)
prevProps.data !== props.data
) {
// 只有父级数据变动的时候才应该进来,
// 目前看来这个 case 很少有情况下能进来

View File

@ -22,6 +22,7 @@ import {
extendDefaultEnv
} from './factory';
import type {RenderOptions, RendererConfig, RendererProps} from './factory';
import './polyfills';
import './renderers/builtin';
import './renderers/register';
export * from './utils/index';

View File

@ -0,0 +1,10 @@
/**
* polyfill
*/
// ios 老版本没有这个会报错
if (!('DragEvent' in window)) {
Object.defineProperty(window, 'DragEvent', {
value: class DragEvent {}
});
}

View File

@ -1110,7 +1110,7 @@ export class FormItemWrap extends React.Component<FormItemProps> {
static: isStatic,
staticClassName
} = props;
const mobileUI = useMobileUI && isMobile();
description = description || desc;
return (
@ -1157,50 +1157,101 @@ export class FormItemWrap extends React.Component<FormItemProps> {
</label>
) : null}
{renderControl()}
{mobileUI ? (
<div className={cx('Form-item-controlBox')}>
{renderControl()}
{caption
? render('caption', caption, {
className: cx(`Form-caption`, captionClassName)
})
: null}
{caption
? render('caption', caption, {
className: cx(`Form-caption`, captionClassName)
})
: null}
{remark
? render('remark', {
type: 'remark',
icon: remark.icon || 'warning-mark',
className: cx(`Form-remark`),
tooltip: remark,
useMobileUI,
container:
env && env.getModalContainer
? env.getModalContainer
: undefined
})
: null}
{remark
? render('remark', {
type: 'remark',
icon: remark.icon || 'warning-mark',
className: cx(`Form-remark`),
tooltip: remark,
useMobileUI,
container:
env && env.getModalContainer
? env.getModalContainer
: undefined
})
: null}
{hint && model && model.isFocused
? render('hint', hint, {
className: cx(`Form-hint`)
})
: null}
{hint && model && model.isFocused
? render('hint', hint, {
className: cx(`Form-hint`)
})
: null}
{model &&
!model.valid &&
showErrorMsg !== false &&
Array.isArray(model.errors) ? (
<ul className={cx(`Form-feedback`)}>
{model.errors.map((msg: string, key: number) => (
<li key={key}>{msg}</li>
))}
</ul>
) : null}
{model &&
!model.valid &&
showErrorMsg !== false &&
Array.isArray(model.errors) ? (
<ul className={cx(`Form-feedback`)}>
{model.errors.map((msg: string, key: number) => (
<li key={key}>{msg}</li>
))}
</ul>
) : null}
{renderDescription !== false && description
? render('description', description, {
className: cx(`Form-description`, descriptionClassName)
})
: null}
{renderDescription !== false && description
? render('description', description, {
className: cx(`Form-description`, descriptionClassName)
})
: null}
</div>
) : (
<>
{renderControl()}
{caption
? render('caption', caption, {
className: cx(`Form-caption`, captionClassName)
})
: null}
{remark
? render('remark', {
type: 'remark',
icon: remark.icon || 'warning-mark',
className: cx(`Form-remark`),
tooltip: remark,
useMobileUI,
container:
env && env.getModalContainer
? env.getModalContainer
: undefined
})
: null}
{hint && model && model.isFocused
? render('hint', hint, {
className: cx(`Form-hint`)
})
: null}
{model &&
!model.valid &&
showErrorMsg !== false &&
Array.isArray(model.errors) ? (
<ul className={cx(`Form-feedback`)}>
{model.errors.map((msg: string, key: number) => (
<li key={key}>{msg}</li>
))}
</ul>
) : null}
{renderDescription !== false && description
? render('description', description, {
className: cx(`Form-description`, descriptionClassName)
})
: null}
</>
)}
</div>
);
},

View File

@ -188,8 +188,8 @@ export const FormStore = ServiceStore.named('FormStore')
// 如果数据域中有数据变化就都reset一下去掉之前残留的验证消息
self.items.forEach(item => {
const value = item.value;
if (typeof value !== 'undefined' && value !== item.tmpValue) {
const value = getVariable(values, item.name);
if (value !== undefined && value !== item.tmpValue) {
item.changeTmpValue(value);
}
item.reset();

View File

@ -162,7 +162,7 @@ export interface BaseApiObject {
/**
* api url
* url traceExpression
* url trackExpression
*/
trackExpression?: string;

View File

@ -1,3 +1,4 @@
import {attachmentAdpator} from 'amis-core';
import omit from 'lodash/omit';
import {Api, ApiObject, EventTrack, fetcherResult, Payload} from '../types';
import {fetcherConfig} from '../factory';
@ -143,6 +144,30 @@ export function buildApi(
}
: undefined
);
/** 追加data到请求的Query中 */
const attachDataToQuery = (
apiObject: ApiObject,
ctx: Record<string, any>
) => {
const idx = apiObject.url.indexOf('?');
if (~idx) {
const params = (apiObject.query = {
...qsparse(apiObject.url.substring(idx + 1)),
...apiObject.query,
...ctx
});
apiObject.url =
apiObject.url.substring(0, idx) + '?' + queryStringify(params);
} else {
apiObject.query = {...apiObject.query, ...ctx};
const query = queryStringify(ctx);
if (query) {
apiObject.url = `${apiObject.url}?${query}`;
}
}
return apiObject;
};
if (~idx) {
const hashIdx = url.indexOf('#');
@ -217,39 +242,11 @@ export function buildApi(
api.data &&
((!~raw.indexOf('$') && autoAppend) || api.forceAppendDataToQuery)
) {
const idx = api.url.indexOf('?');
if (~idx) {
let params = (api.query = {
...qsparse(api.url.substring(idx + 1)),
...api.query,
...data
});
api.url = api.url.substring(0, idx) + '?' + queryStringify(params);
} else {
api.query = {...api.query, ...data};
const query = queryStringify(data);
if (query) {
api.url = `${api.url}?${query}`;
}
}
api = attachDataToQuery(api, data);
}
if (api.data && api.attachDataToQuery !== false) {
const idx = api.url.indexOf('?');
if (~idx) {
let params = (api.query = {
...qsparse(api.url.substring(idx + 1)),
...api.query,
...api.data
});
api.url = api.url.substring(0, idx) + '?' + queryStringify(params);
} else {
api.query = {...api.query, ...api.data};
const query = queryStringify(api.query);
if (query) {
api.url = `${api.url}?${query}`;
}
}
api = attachDataToQuery(api, data);
delete api.data;
}
}
@ -302,6 +299,11 @@ export function buildApi(
jsonql: api.jsonql
}
: api.jsonql;
/** JSONQL所有method需要追加data中的变量到query中 */
if (api.forceAppendDataToQuery) {
api = attachDataToQuery(api, data);
}
}
return api;

View File

@ -321,6 +321,8 @@ $tooltip-bottom: '[data-tooltip][data-position=' bottom ']:hover:after';
width: 100%;
--Tabs--line-active-fontSize: 14px;
--Tabs--line-fontSize: 14px;
--Tabs--line-hover-fontSize: 14px;
--Tabs--line-disabled-fontSize: 14px;
letter-spacing: 0;
font-weight: 400;
text-decoration: none;

View File

@ -60,4 +60,19 @@
text-align: center;
}
}
&-dragBar {
position: absolute;
display: none;
z-index: 2;
top: 50%;
transform: translateY(-50%);
left: 3px;
cursor: pointer;
}
&:hover &-dragBar {
display: block;
color: #fff;
}
}

View File

@ -21,8 +21,15 @@
}
&:hover {
border: none;
&.ae-FeatureControlItem-go {
color: transparent;
}
.ae-GoConfig-trigger {
display: block;
border-radius: $Editor-borderRadius;
}
}
}

View File

@ -81,7 +81,7 @@
}
&-fxIcon {
> a {
font-size: 18px;
font-size: 14px;
}
}
}
@ -130,7 +130,7 @@
}
&-fxIcon {
> a {
font-size: 28px;
font-size: 20px;
}
}
}

View File

@ -102,7 +102,12 @@ export interface DSSourceSettingFormConfig {
grain?: DSGrain;
/** 数据源所被使用的功能场景 */
feat: DSFeatureType;
/** 是否是在CRUD场景下有的数据源在CRUD中可以统一设置 */
/** 渲染器类型 */
renderer?: string;
/**
* @deprecated 使renderer字段代替
* CRUD场景下CRUD中可以统一设置
* */
inCrud?: boolean;
/** 是否在脚手架中 */
inScaffold?: boolean;

View File

@ -33,7 +33,7 @@ import SearchPanel from './component/base/SearchPanel';
import {VRenderer} from './component/VRenderer';
import {RegionWrapper} from './component/RegionWrapper';
import {mapReactElement} from './component/factory';
import type {EditorNodeType} from './store/node';
import type {EditorNodeType, EditorNodeSnapshot} from './store/node';
import {ContainerWrapper} from './component/ContainerWrapper';
import type {EditorStoreType} from './store/editor';
import {AvailableRenderersPlugin} from './plugin/AvailableRenderers';
@ -56,6 +56,7 @@ export {
IFramePreview as IFrameEditor,
SearchPanel,
EditorNodeType,
EditorNodeSnapshot,
EditorStoreType,
ContainerWrapper,
AvailableRenderersPlugin,

View File

@ -2,8 +2,12 @@
* @file 西 compoennt/Editor.tsx
* UI 西
*/
import uniqBy from 'lodash/uniqBy';
import {reaction} from 'mobx';
import {parse, stringify} from 'json-ast-comments';
import debounce from 'lodash/debounce';
import findIndex from 'lodash/findIndex';
import omit from 'lodash/omit';
import {openContextMenus, toast, alert, DataScope, DataSchema} from 'amis';
import {getRenderers, RenderOptions, mapTree} from 'amis-core';
import {
PluginInterface,
@ -31,14 +35,14 @@ import {
DeleteEventContext,
RendererPluginEvent,
PluginEvents,
PluginActions
PluginActions,
BasePlugin
} from './plugin';
import {
EditorStoreType,
PopOverFormContext,
SubEditorContext
} from './store/editor';
import {
autobind,
camelize,
@ -49,29 +53,18 @@ import {
isString,
isObject,
isLayoutPlugin,
JSONPipeOut,
generateNodeId,
JSONTraverse
JSONPipeOut
} from './util';
import {reaction} from 'mobx';
import {hackIn, makeSchemaFormRender, makeWrapper} from './component/factory';
import {env} from './env';
import debounce from 'lodash/debounce';
import sortBy from 'lodash/sortBy';
import reverse from 'lodash/reverse';
import cloneDeep from 'lodash/cloneDeep';
import {openContextMenus, toast, alert, DataScope, DataSchema} from 'amis';
import {parse, stringify} from 'json-ast-comments';
import {EditorNodeType} from './store/node';
import {EditorProps} from './component/Editor';
import findIndex from 'lodash/findIndex';
import {EditorDNDManager} from './dnd';
import {VariableManager} from './variable';
import {IScopedContext} from 'amis';
import type {IScopedContext} from 'amis';
import type {SchemaObject, SchemaCollection} from 'amis';
import type {RendererConfig} from 'amis-core';
import isPlainObject from 'lodash/isPlainObject';
import {omit} from 'lodash';
export interface EditorManagerConfig
extends Omit<EditorProps, 'value' | 'onChange'> {}
@ -79,6 +72,8 @@ export interface EditorManagerConfig
export interface PluginClass {
new (manager: EditorManager, options?: any): PluginInterface;
id?: string;
/** 优先级值为整数当存在两个ID相同的Plugin时数字更大的优先级更高 */
priority?: number;
scene?: Array<string>;
}
@ -111,22 +106,58 @@ export function registerEditorPlugin(klass: PluginClass) {
// 处理插件身上的场景信息
const scene = Array.from(new Set(['global'].concat(klass.scene || 'global')));
klass.scene = scene;
let isExitPlugin: any = null;
let exsitedPluginIdx: any = null;
if (klass.prototype && klass.prototype.isNpmCustomWidget) {
isExitPlugin = builtInPlugins.find(item =>
exsitedPluginIdx = builtInPlugins.findIndex(item =>
Array.isArray(item)
? item[0].prototype.name === klass.prototype.name
: item.prototype.name === klass.prototype.name
);
} else {
// 待进一步优化
isExitPlugin = builtInPlugins.find(item => item === klass);
exsitedPluginIdx = builtInPlugins.findIndex(item => item === klass);
}
if (!isExitPlugin) {
/** 先给新加入的plugin加一个ID */
if (!~exsitedPluginIdx) {
klass.id = klass.id || klass.name || guid();
builtInPlugins.push(klass);
}
/** 因为class的继承关系未设置ID的子class会和父class共用ID, 只有设置了priority的时候才会执行同ID去重 */
if (klass.priority == null || !Number.isInteger(klass.priority)) {
if (!~exsitedPluginIdx) {
builtInPlugins.push(klass);
} else {
console.warn(`注册插件「${klass.id}」异常,已存在同名插件:`, klass);
}
} else {
console.warn(`注册插件异常,已存在同名插件:`, klass);
exsitedPluginIdx = ~exsitedPluginIdx
? exsitedPluginIdx
: builtInPlugins.findIndex(
item =>
!Array.isArray(item) &&
item.id === klass.id &&
item?.prototype instanceof BasePlugin
);
if (!~exsitedPluginIdx) {
builtInPlugins.push(klass);
} else {
const current = builtInPlugins[exsitedPluginIdx] as PluginClass;
/** 同ID的插件根据优先级决定是否update */
const currentPriority =
current.priority && Number.isInteger(current.priority)
? current.priority
: 0;
if (klass.priority > currentPriority) {
builtInPlugins.splice(exsitedPluginIdx, 1, klass);
} else {
console.warn(`注册插件「${klass.id}」异常,已存在同名插件:`, klass);
}
}
}
}
@ -199,7 +230,39 @@ export class EditorManager {
this.hackIn = parent?.hackIn || hackIn;
// 自动加载预先注册的自定义组件
autoPreRegisterEditorCustomPlugins();
const scene = config.scene || 'global';
/** 在顶层对外部注册的Plugin和builtInPlugins合并去重 */
if (!parent?.plugins) {
(config?.plugins || []).forEach(external => {
if (
Array.isArray(external) ||
!external.priority ||
!Number.isInteger(external.priority)
) {
return;
}
const idx = builtInPlugins.findIndex(
builtIn =>
!Array.isArray(builtIn) &&
!Array.isArray(external) &&
builtIn.id === external.id &&
builtIn?.prototype instanceof BasePlugin
);
if (~idx) {
const current = builtInPlugins[idx] as PluginClass;
const currentPriority =
current.priority && Number.isInteger(current.priority)
? current.priority
: 0;
/** 同ID Plugin根据优先级决定是否替换掉Builtin中的Plugin */
if (external.priority > currentPriority) {
builtInPlugins.splice(idx, 1);
}
}
});
}
this.plugins =
parent?.plugins ||
(config.disableBultinPlugin ? [] : builtInPlugins) // 页面设计器注册的插件列表

View File

@ -291,6 +291,8 @@ export interface RendererInfo extends RendererScaffoldInfo {
memberIndex?: number;
tipName?: string;
/** 共享上下文 */
sharedContext?: Record<string, any>;
}
export type BasicRendererInfo = Omit<

View File

@ -77,6 +77,14 @@ export const EditorNode = types
info = value;
},
updateSharedContext(value: Record<string, any>) {
if (!value || !info?.hasOwnProperty('sharedContext')) {
return;
}
info.sharedContext = value;
},
get rendererConfig() {
return rendererConfig;
},

View File

@ -5,6 +5,7 @@ import {getSchemaTpl} from 'amis-editor-core';
import type {SchemaObject} from 'amis';
export class AlertPlugin extends BasePlugin {
static id = 'AlertPlugin';
static scene = ['layout'];
// 关联渲染器名字

View File

@ -11,6 +11,7 @@ import {registerFilter} from 'amis-formula';
registerFilter('appTranslate', (input: any) => translateSchema(input));
export class AnchorNavPlugin extends BasePlugin {
static id = 'AnchorNavPlugin';
// 关联渲染器名字
rendererName = 'anchor-nav';
$schema = '/schemas/AnchorNavSchema.json';

View File

@ -3,6 +3,7 @@ import {BaseEventContext, BasePlugin} from 'amis-editor-core';
import {defaultValue, getSchemaTpl} from 'amis-editor-core';
export class AudioPlugin extends BasePlugin {
static id = 'AudioPlugin';
static scene = ['layout'];
// 关联渲染器名字
rendererName = 'audio';

View File

@ -13,6 +13,7 @@ const widthOrheightPipeIn = (curValue: string, rest: any) =>
curValue ? curValue : rest.data?.size ?? DefaultSize;
export class AvatarPlugin extends BasePlugin {
static id = 'AvatarPlugin';
static scene = ['layout'];
// 关联渲染器名字
rendererName = 'avatar';

View File

@ -6,6 +6,7 @@ import {BaseEventContext, BasePlugin} from 'amis-editor-core';
import {getSchemaTpl} from 'amis-editor-core';
export class BreadcrumbPlugin extends BasePlugin {
static id = 'BreadcrumbPlugin';
// 关联渲染器名字
rendererName = 'breadcrumb';
$schema = '/schemas/BreadcrumbSchema.json';

View File

@ -15,6 +15,7 @@ import type {SchemaObject} from 'amis';
import {getOldActionSchema} from '../renderer/event-control/helper';
export class ButtonPlugin extends BasePlugin {
static id = 'ButtonPlugin';
static scene = ['layout'];
// 关联渲染器名字
rendererName = 'button';

View File

@ -11,6 +11,7 @@ import {
import {BUTTON_DEFAULT_ACTION} from '../component/BaseControl';
export class ButtonGroupPlugin extends BasePlugin {
static id = 'ButtonGroupPlugin';
static scene = ['layout'];
// 关联渲染器名字
rendererName = 'button-group';

View File

@ -56,6 +56,7 @@ const viewTypeToEditType = (type: string) => {
};
export class CRUDPlugin extends BasePlugin {
static id = 'CRUDPlugin';
// 关联渲染器名字
rendererName = 'crud';
$schema = '/schemas/CRUDSchema.json';

View File

@ -477,6 +477,7 @@ const DataOperators: Array<FeatOption> = [
];
export class CRUDPlugin extends BasePlugin {
static id = 'CRUD2Plugin';
constructor(manager: EditorManager) {
super(manager);
this.dsBuilderMgr = new DSBuilderManager('crud2', 'api');

View File

@ -18,6 +18,7 @@ import flatten from 'lodash/flatten';
import {VRenderer} from 'amis-editor-core';
export class CardPlugin extends BasePlugin {
static id = 'CardPlugin';
static scene = ['layout'];
// 关联渲染器名字
rendererName = 'card';

View File

@ -9,6 +9,7 @@ import {
} from 'amis-editor-core';
export class Card2Plugin extends BasePlugin {
static id = 'Card2Plugin';
static scene = ['layout'];
// 关联渲染器名字
rendererName = 'card2';

View File

@ -19,6 +19,7 @@ import {diff, JSONPipeOut, repeatArray} from 'amis-editor-core';
import {resolveArrayDatasource} from '../util';
export class CardsPlugin extends BasePlugin {
static id = 'CardsPlugin';
static scene = ['layout'];
// 关联渲染器名字
rendererName = 'cards';

View File

@ -4,6 +4,7 @@ import {defaultValue, getSchemaTpl} from 'amis-editor-core';
import {mockValue} from 'amis-editor-core';
export class CarouselPlugin extends BasePlugin {
static id = 'CarouselPlugin';
// 关联渲染器名字
rendererName = 'carousel';
$schema = '/schemas/CarouselSchema.json';

View File

@ -76,6 +76,7 @@ const DEFAULT_EVENT_PARAMS = [
];
export class ChartPlugin extends BasePlugin {
static id = 'ChartPlugin';
// 关联渲染器名字
rendererName = 'chart';
$schema = '/schemas/ChartSchema.json';

View File

@ -6,6 +6,7 @@ import {BaseEventContext, BasePlugin} from 'amis-editor-core';
import {getSchemaTpl} from 'amis-editor-core';
export class CodeViewPlugin extends BasePlugin {
static id = 'CodeViewPlugin';
// 关联渲染器名字
rendererName = 'code';
$schema = '/schemas/CodeSchema.json';

View File

@ -3,6 +3,7 @@ import {BasePlugin, RegionConfig, BaseEventContext} from 'amis-editor-core';
import {defaultValue, getSchemaTpl} from 'amis-editor-core';
export class CollapsePlugin extends BasePlugin {
static id = 'CollapsePlugin';
// 关联渲染器名字
rendererName = 'collapse';
$schema = '/schemas/CollapseSchema.json';

View File

@ -6,6 +6,7 @@ import {tipedLabel} from 'amis-editor-core';
import {isObject} from 'amis-editor-core';
export class CollapseGroupPlugin extends BasePlugin {
static id = 'CollapseGroupPlugin';
// 关联渲染器名字
rendererName = 'collapse-group';
$schema = '/schemas/CollapseGroupSchema.json';

View File

@ -9,6 +9,7 @@ import {
} from 'amis-editor-core';
export class ColumnToggler extends BasePlugin {
static id = 'ColumnToggler';
// 关联渲染器名字
rendererName = 'column-toggler';
$schema = '/schemas/ColumnToggler.json';

View File

@ -11,6 +11,7 @@ import {
} from 'amis-editor-core';
export class ContainerPlugin extends LayoutBasePlugin {
static id = 'ContainerPlugin';
static scene = ['layout'];
// 关联渲染器名字
rendererName = 'container';

View File

@ -12,6 +12,7 @@ import {
import {getSchemaTpl} from 'amis-editor-core';
export class CustomPlugin extends BasePlugin {
static id = 'CustomPlugin';
// 关联渲染器名字
rendererName = 'custom';
$schema = '/schemas/CustomSchema.json';

View File

@ -15,6 +15,7 @@ import {defaultValue, getSchemaTpl} from 'amis-editor-core';
import isArray from 'lodash/isArray';
export class CustomPlugin extends BasePlugin {
static id = 'CustomRegionPlugin';
// 关联渲染器名字
rendererName = 'custom';
$schema = '/schemas/CustomSchema.json';

View File

@ -31,6 +31,7 @@ const valueDateFormatOptions = [
}
];
export class DatePlugin extends BasePlugin {
static id = 'DatePlugin';
static scene = ['layout'];
// 关联渲染器名字
rendererName = 'date';

View File

@ -32,6 +32,7 @@ const valueDateFormatOptions = [
}
];
export class DatetimePlugin extends DatePlugin {
static id = 'DatetimePlugin';
static scene = ['layout'];
// 关联渲染器名字
rendererName = 'datetime';

View File

@ -13,6 +13,7 @@ import {
import {getEventControlConfig} from '../renderer/event-control/helper';
export class DialogPlugin extends BasePlugin {
static id = 'DialogPlugin';
// 关联渲染器名字
rendererName = 'dialog';
$schema = '/schemas/DialogSchema.json';

View File

@ -3,6 +3,7 @@ import {BasePlugin} from 'amis-editor-core';
import {getSchemaTpl} from 'amis-editor-core';
export class DividerPlugin extends BasePlugin {
static id = 'DividerPlugin';
static scene = ['layout'];
// 关联渲染器名字
rendererName = 'divider';

View File

@ -13,6 +13,7 @@ import {InlineModal} from './Dialog';
import {tipedLabel} from 'amis-editor-core';
export class DrawerPlugin extends BasePlugin {
static id = 'DrawerPlugin';
// 关联渲染器名字
rendererName = 'drawer';
$schema = '/schemas/DrawerSchema.json';

View File

@ -14,6 +14,7 @@ import {
} from 'amis-editor-core';
import {BUTTON_DEFAULT_ACTION} from '../component/BaseControl';
export class DropDownButtonPlugin extends BasePlugin {
static id = 'DropDownButtonPlugin';
static scene = ['layout'];
// 关联渲染器名字
rendererName = 'dropdown-button';

View File

@ -12,6 +12,7 @@ import {defaultValue, getSchemaTpl} from 'amis-editor-core';
import {diff, JSONPipeOut} from 'amis-editor-core';
export class EachPlugin extends BasePlugin {
static id = 'EachPlugin';
static scene = ['layout'];
// 关联渲染器名字
rendererName = 'each';

View File

@ -5,6 +5,7 @@ import {registerEditorPlugin} from 'amis-editor-core';
import {FlexPluginBase} from './Layout/FlexPluginBase';
export class FlexPlugin extends FlexPluginBase {
static id = 'FlexPlugin';
static scene = ['layout'];
name = 'Flex 布局';
pluginIcon = 'flex-container-plugin';

View File

@ -10,6 +10,7 @@ import {getSchemaTpl, defaultValue} from 'amis-editor-core';
import {getEventControlConfig} from '../../renderer/event-control/helper';
export class ButtonGroupControlPlugin extends BasePlugin {
static id = 'ButtonGroupControlPlugin';
// 关联渲染器名字
rendererName = 'button-group-select';
$schema = '/schemas/ButtonGroupControlSchema.json';

View File

@ -8,6 +8,7 @@ import {
} from '../../component/BaseControl';
export class ButtonToolbarControlPlugin extends BasePlugin {
static id = 'ButtonToolbarControlPlugin';
static scene = ['layout'];
// 关联渲染器名字
rendererName = 'button-toolbar';

View File

@ -15,6 +15,7 @@ import {ValidatorTag} from '../../validator';
import {getEventControlConfig} from '../../renderer/event-control/helper';
export class ChainedSelectControlPlugin extends BasePlugin {
static id = 'ChainedSelectControlPlugin';
// 关联渲染器名字
rendererName = 'chained-select';
$schema = '/schemas/ChainedSelectControlSchema.json';

View File

@ -23,6 +23,7 @@ setSchemaTpl('option', {
label: tipedLabel('说明', '选项说明')
});
export class CheckboxControlPlugin extends BasePlugin {
static id = 'CheckboxControlPlugin';
static scene = ['layout'];
// 关联渲染器名字
rendererName = 'checkbox';
@ -159,7 +160,9 @@ export class CheckboxControlPlugin extends BasePlugin {
getSchemaTpl('labelRemark'),
getSchemaTpl('remark'),
getSchemaTpl('description'),
getSchemaTpl('autoFillApi')
getSchemaTpl('autoFillApi', {
trigger: 'change'
})
]
},
getSchemaTpl('status', {isFormItem: true}),

View File

@ -18,6 +18,7 @@ import {RendererPluginAction, RendererPluginEvent} from 'amis-editor-core';
import {getEventControlConfig} from '../../renderer/event-control/helper';
export class CheckboxesControlPlugin extends BasePlugin {
static id = 'CheckboxesControlPlugin';
// 关联渲染器名字
rendererName = 'checkboxes';
$schema = '/schemas/CheckboxesControlSchema.json';
@ -171,7 +172,9 @@ export class CheckboxesControlPlugin extends BasePlugin {
getSchemaTpl('labelRemark'),
getSchemaTpl('remark'),
getSchemaTpl('description'),
getSchemaTpl('autoFillApi')
getSchemaTpl('autoFillApi', {
trigger: 'change'
})
]
},
{

View File

@ -9,6 +9,7 @@ import {RendererPluginEvent, RendererPluginAction} from 'amis-editor-core';
import {getEventControlConfig} from '../../renderer/event-control/helper';
export class CodeEditorControlPlugin extends BasePlugin {
static id = 'CodeEditorControlPlugin';
// 关联渲染器名字
rendererName = 'editor';
$schema = '/schemas/EditorControlSchema.json';

View File

@ -23,6 +23,7 @@ import {
} from '../../renderer/event-control/helper';
export class ComboControlPlugin extends BasePlugin {
static id = 'ComboControlPlugin';
// 关联渲染器名字
rendererName = 'combo';
$schema = '/schemas/ComboControlSchema.json';
@ -665,24 +666,31 @@ export class ComboControlPlugin extends BasePlugin {
target: EditorNodeType,
region?: EditorNodeType
) {
if (target.parent.isRegion && target.parent.region === 'items') {
const scope = scopeNode.parent.parent;
const builder = this.dsBuilderManager.resolveBuilderBySchema(
let scope;
let builder;
if (
target.type === scopeNode.type ||
(target.parent.isRegion && target.parent.region === 'items')
) {
scope = scopeNode.parent.parent;
builder = this.dsBuilderManager.resolveBuilderBySchema(
scope.schema,
'api'
);
}
if (builder && scope.schema.api) {
return builder.getAvailableContextFileds(
{
schema: scope.schema,
sourceKey: 'api',
feat: scope.schema?.feat ?? 'List',
scopeNode
},
target
);
}
if (builder && scope.schema.api) {
return builder.getAvailableContextFileds(
{
schema: scope.schema,
sourceKey: 'api',
feat: scope.schema?.feat ?? 'List',
scopeNode
},
/** ID相同为本体否则为子项 */
target?.id === scopeNode?.id ? scopeNode : target
);
}
}
}

View File

@ -16,6 +16,7 @@ import defaultConfig, {
} from 'amis-ui/lib/components/condition-builder/config';
export class ConditionBilderPlugin extends BasePlugin {
static id = 'ConditionBilderPlugin';
// 关联渲染器名字
rendererName = 'condition-builder';
$schema = '/schemas/ConditionBuilderControlSchema.json';

View File

@ -6,6 +6,7 @@ import {BasePlugin, RegionConfig, BaseEventContext} from 'amis-editor-core';
import {formItemControl} from '../../component/BaseControl';
export class ControlPlugin extends BasePlugin {
static id = 'ControlPlugin';
// 关联渲染器名字
rendererName = 'control';
$schema = '/schemas/FormControlSchema.json';

View File

@ -14,6 +14,7 @@ import {getEventControlConfig} from '../../renderer/event-control/helper';
import {RendererPluginEvent, RendererPluginAction} from 'amis-editor-core';
export class DiffEditorControlPlugin extends BasePlugin {
static id = 'DiffEditorControlPlugin';
// 关联渲染器名字
rendererName = 'diff-editor';
$schema = '/schemas/DiffEditorControlSchema.json';

View File

@ -5,6 +5,7 @@ import {registerEditorPlugin} from 'amis-editor-core';
import {BaseEventContext, BasePlugin, RegionConfig} from 'amis-editor-core';
export class FieldSetControlPlugin extends BasePlugin {
static id = 'FieldSetControlPlugin';
// 关联渲染器名字
rendererName = 'fieldset';
$schema = '/schemas/FieldSetControlSchema.json';

View File

@ -124,6 +124,7 @@ const autoAddOptions = (values: any) => {
};
export class FormPlugin extends BasePlugin {
static id = 'FormPlugin';
// 关联渲染器名字
rendererName = 'form';
$schema = '/schemas/FormSchema.json';

View File

@ -3,6 +3,7 @@ import {registerEditorPlugin} from 'amis-editor-core';
import {BasePlugin} from 'amis-editor-core';
export class FormulaControlPlugin extends BasePlugin {
static id = 'FormulaControlPlugin';
// 关联渲染器名字
rendererName = 'formula';
$schema = '/schemas/FormulaControlSchema.json';

View File

@ -11,6 +11,7 @@ import {defaultValue, getSchemaTpl} from 'amis-editor-core';
import {JSONPipeIn, JSONUpdate, makeHorizontalDeeper} from 'amis-editor-core';
export class GroupControlPlugin extends BasePlugin {
static id = 'GroupControlPlugin';
// 关联渲染器名字
rendererName = 'group';
$schema = '/schemas/GroupControlSchema.json';

View File

@ -3,6 +3,7 @@ import {registerEditorPlugin} from 'amis-editor-core';
import {BasePlugin, getSchemaTpl} from 'amis-editor-core';
export class HiddenControlPlugin extends BasePlugin {
static id = 'HiddenControlPlugin';
// 关联渲染器名字
rendererName = 'hidden';
$schema = '/schemas/HiddenControlSchema.json';

View File

@ -15,6 +15,7 @@ import React from 'react';
import {diff, JSONPipeOut} from 'amis-editor-core';
export class ArrayControlPlugin extends BasePlugin {
static id = 'ArrayControlPlugin';
// 关联渲染器名字
rendererName = 'input-array';
$schema = '/schemas/ArrayControlSchema.json';

View File

@ -15,6 +15,7 @@ import {ValidatorTag} from '../../validator';
import {getEventControlConfig} from '../../renderer/event-control/helper';
export class CityControlPlugin extends BasePlugin {
static id = 'CityControlPlugin';
static scene = ['layout'];
// 关联渲染器名字
rendererName = 'input-city';

View File

@ -55,6 +55,7 @@ const presetColorsByFormat = colorFormat.reduce<{
return res;
}, {});
export class ColorControlPlugin extends BasePlugin {
static id = 'ColorControlPlugin';
static scene = ['layout'];
// 关联渲染器名字
rendererName = 'input-color';

View File

@ -140,6 +140,7 @@ const dateTooltip =
'支持例如: <code>now、+3days、-2weeks、+1hour、+2years</code> 等minute|min|hour|day|week|month|year|weekday|second|millisecond这种相对值用法';
export class DateControlPlugin extends BasePlugin {
static id = 'DateControlPlugin';
// 关联渲染器名字
rendererName = 'input-date';
$schema = '/schemas/DateControlSchema.json';

View File

@ -181,6 +181,7 @@ const sizeImmutableComponents = Object.values(DateType)
.filter(a => a);
export class DateRangeControlPlugin extends BasePlugin {
static id = 'DateRangeControlPlugin';
// 关联渲染器名字
rendererName = 'input-date-range';
$schema = '/schemas/DateRangeControlSchema.json';

View File

@ -3,6 +3,7 @@ import {registerEditorPlugin} from 'amis-editor-core';
import {DateControlPlugin} from './InputDate';
export class DateTimeControlPlugin extends DateControlPlugin {
static id = 'DateTimeControlPlugin';
// 关联渲染器名字
rendererName = 'input-datetime';
$schema = '/schemas/DateTimeControlSchema.json';

View File

@ -3,6 +3,7 @@ import {registerEditorPlugin} from 'amis-editor-core';
import {DateRangeControlPlugin} from './InputDateRange';
export class DateTimeRangeControlPlugin extends DateRangeControlPlugin {
static id = 'DateTimeRangeControlPlugin';
// 关联渲染器名字
rendererName = 'input-datetime-range';
$schema = '/schemas/DateTimeRangeControlSchema.json';

View File

@ -2,6 +2,7 @@ import {registerEditorPlugin} from 'amis-editor-core';
import {TextControlPlugin} from './InputText';
export class EmailControlPlugin extends TextControlPlugin {
static id = 'EmailControlPlugin';
// 关联渲染器名字
rendererName = 'input-email';
$schema = '/schemas/TextControlSchema.json';

View File

@ -14,6 +14,7 @@ import {formItemControl} from '../../component/BaseControl';
import {RendererPluginAction, RendererPluginEvent} from 'amis-editor-core';
export class ExcelControlPlugin extends BasePlugin {
static id = 'ExcelControlPlugin';
// 关联渲染器名字
rendererName = 'input-excel';
$schema = '/schemas/ExcelControlSchema.json';

View File

@ -6,6 +6,7 @@ import {getEventControlConfig} from '../../renderer/event-control/helper';
import {RendererPluginAction, RendererPluginEvent} from 'amis-editor-core';
export class FileControlPlugin extends BasePlugin {
static id = 'FileControlPlugin';
// 关联渲染器名字
rendererName = 'input-file';
$schema = '/schemas/FileControlSchema.json';

View File

@ -10,6 +10,7 @@ import {
import {ValidatorTag} from '../../validator';
export class InputGroupControlPlugin extends BasePlugin {
static id = 'InputGroupControlPlugin';
static scene = ['layout'];
// 关联渲染器名字
rendererName = 'input-group';

View File

@ -48,6 +48,7 @@ const inputStateFunc = (visibleOn: string, state: string) => {
};
export class ImageControlPlugin extends BasePlugin {
static id = 'ImageControlPlugin';
// 关联渲染器名字
rendererName = 'input-image';
$schema = '/schemas/ImageControlSchema.json';

View File

@ -12,6 +12,7 @@ import {
} from 'amis-editor-core';
export class KVControlPlugin extends BasePlugin {
static id = 'KVControlPlugin';
static scene = ['layout'];
// 关联渲染器名字
rendererName = 'input-kv';

View File

@ -3,6 +3,7 @@ import {registerEditorPlugin} from 'amis-editor-core';
import {DateControlPlugin} from './InputDate';
export class MonthControlPlugin extends DateControlPlugin {
static id = 'MonthControlPlugin';
// 关联渲染器名字
rendererName = 'input-month';
$schema = '/schemas/MonthControlSchema.json';

View File

@ -3,6 +3,7 @@ import {registerEditorPlugin} from 'amis-editor-core';
import {DateRangeControlPlugin} from './InputDateRange';
export class MonthRangeControlPlugin extends DateRangeControlPlugin {
static id = 'MonthRangeControlPlugin';
// 关联渲染器名字
rendererName = 'input-month-range';
$schema = '/schemas/MonthRangeControlSchema.json';

View File

@ -20,6 +20,7 @@ import {getEventControlConfig} from '../../renderer/event-control/helper';
import {inputStateTpl} from '../../renderer/style-control/helper';
export class NumberControlPlugin extends BasePlugin {
static id = 'NumberControlPlugin';
// 关联渲染器名字
rendererName = 'input-number';
$schema = '/schemas/NumberControlSchema.json';

View File

@ -2,6 +2,7 @@ import {registerEditorPlugin} from 'amis-editor-core';
import {TextControlPlugin} from './InputText';
export class PasswordControlPlugin extends TextControlPlugin {
static id = 'PasswordControlPlugin';
// 关联渲染器名字
rendererName = 'input-password';
$schema = '/schemas/TextControlSchema.json';

View File

@ -3,6 +3,7 @@ import {registerEditorPlugin} from 'amis-editor-core';
import {DateControlPlugin} from './InputDate';
export class InputQuarterPlugin extends DateControlPlugin {
static id = 'InputQuarterPlugin';
// 关联渲染器名字
rendererName = 'input-quarter';
$schema = '/schemas/QuarterControlSchema.json';

View File

@ -3,6 +3,7 @@ import {registerEditorPlugin} from 'amis-editor-core';
import {DateRangeControlPlugin} from './InputDateRange';
export class QuarterRangePlugin extends DateRangeControlPlugin {
static id = 'QuarterRangePlugin';
// 关联渲染器名字
rendererName = 'input-quarter-range';
$schema = '/schemas/MonthRangeControlSchema.json';

View File

@ -6,6 +6,7 @@ import {ValidatorTag} from '../../validator';
import {getEventControlConfig} from '../../renderer/event-control/helper';
export class RangeControlPlugin extends BasePlugin {
static id = 'RangeControlPlugin';
// 关联渲染器名字
rendererName = 'input-range';
$schema = '/schemas/RangeControlSchema.json';

View File

@ -12,6 +12,7 @@ import {getEventControlConfig} from '../../renderer/event-control/helper';
import {RendererPluginAction, RendererPluginEvent} from 'amis-editor-core';
export class RateControlPlugin extends BasePlugin {
static id = 'RateControlPlugin';
// 关联渲染器名字
rendererName = 'input-rating';
$schema = '/schemas/RatingControlSchema.json';

View File

@ -3,6 +3,7 @@ import {registerEditorPlugin} from 'amis-editor-core';
import {BasePlugin} from 'amis-editor-core';
export class RepeatControlPlugin extends BasePlugin {
static id = 'RepeatControlPlugin';
// 关联渲染器名字
rendererName = 'input-repeat';
$schema = '/schemas/RepeatControlSchema.json';

View File

@ -150,6 +150,7 @@ const froalaOptionsPipeOut = (arr: Array<string>) => {
};
export class RichTextControlPlugin extends BasePlugin {
static id = 'RichTextControlPlugin';
// 关联渲染器名字
rendererName = 'input-rich-text';
$schema = '/schemas/RichTextControlSchema.json';

View File

@ -14,6 +14,7 @@ import {
} from 'amis-editor-core';
export class SubFormControlPlugin extends BasePlugin {
static id = 'SubFormControlPlugin';
// 关联渲染器名字
rendererName = 'input-sub-form';
$schema = '/schemas/SubFormControlSchema.json';

View File

@ -28,6 +28,7 @@ import cloneDeep from 'lodash/cloneDeep';
import {resolveArrayDatasource} from '../../util';
export class TableControlPlugin extends BasePlugin {
static id = 'TableControlPlugin';
// 关联渲染器名字
rendererName = 'input-table';
$schema = '/schemas/TableControlSchema.json';
@ -1111,16 +1112,28 @@ export class TableControlPlugin extends BasePlugin {
const columns: EditorNodeType = node.children.find(
item => item.isRegion && item.region === 'columns'
);
for (let current of columns?.children) {
const schema = current.schema;
if (schema.name) {
itemsSchema.properties[schema.name] = current.info?.plugin
?.buildDataSchemas
? await current.info.plugin.buildDataSchemas(current, region)
: {
type: 'string',
title: schema.label || schema.name
};
// todo以下的处理无效需要cell实现才能深层细化
// for (let current of columns?.children) {
// const schema = current.schema;
// if (schema.name) {
// itemsSchema.properties[schema.name] = current.info?.plugin
// ?.buildDataSchemas
// ? await current.info.plugin.buildDataSchemas(current, region)
// : {
// type: 'string',
// title: schema.label || schema.name
// };
// }
// }
// 一期先简单处理上面todo实现之后这里可以废弃
for (let current of node.schema?.columns) {
if (current.name) {
itemsSchema.properties[current.name] = {
type: 'string',
title: current.label || current.name
};
}
}
@ -1141,24 +1154,31 @@ export class TableControlPlugin extends BasePlugin {
target: EditorNodeType,
region?: EditorNodeType
) {
if (target.parent.isRegion && target.parent.region === 'columns') {
const scope = scopeNode.parent.parent;
const builder = this.dsBuilderManager.resolveBuilderBySchema(
let scope;
let builder;
if (
target.type === scopeNode.type ||
(target.parent.isRegion && target.parent.region === 'columns')
) {
scope = scopeNode.parent.parent;
builder = this.dsBuilderManager.resolveBuilderBySchema(
scope.schema,
'api'
);
}
if (builder && scope.schema.api) {
return builder.getAvailableContextFileds(
{
schema: scope.schema,
sourceKey: 'api',
feat: scope.schema?.feat ?? 'List',
scopeNode
},
target
);
}
if (builder && scope.schema.api) {
return builder.getAvailableContextFileds(
{
schema: scope.schema,
sourceKey: 'api',
feat: scope.schema?.feat ?? 'List',
scopeNode
},
/** ID相同为本体否则为子项 */
target?.id === scopeNode?.id ? scopeNode : target
);
}
}
}

View File

@ -12,6 +12,7 @@ import {formItemControl} from '../../component/BaseControl';
import {RendererPluginAction, RendererPluginEvent} from 'amis-editor-core';
export class TagControlPlugin extends BasePlugin {
static id = 'TagControlPlugin';
static scene = ['layout'];
// 关联渲染器名字
rendererName = 'input-tag';

View File

@ -20,6 +20,7 @@ function isTextShow(value: string, name: boolean): boolean {
}
export class TextControlPlugin extends BasePlugin {
static id = 'TextControlPlugin';
static scene = ['layout'];
// 关联渲染器名字
rendererName = 'input-text';

View File

@ -2,6 +2,7 @@ import {registerEditorPlugin} from 'amis-editor-core';
import {DateControlPlugin} from './InputDate';
export class TimeControlPlugin extends DateControlPlugin {
static id = 'TimeControlPlugin';
// 关联渲染器名字
rendererName = 'input-time';
$schema = '/schemas/TimeControlSchema.json';

View File

@ -3,6 +3,7 @@ import {registerEditorPlugin} from 'amis-editor-core';
import {DateRangeControlPlugin} from './InputDateRange';
export class TimeRangeControlPlugin extends DateRangeControlPlugin {
static id = 'TimeRangeControlPlugin';
// 关联渲染器名字
rendererName = 'input-time-range';
$schema = '/schemas/DateRangeControlSchema.json';

View File

@ -16,6 +16,7 @@ import {tipedLabel} from 'amis-editor-core';
import {ValidatorTag} from '../../validator';
export class TreeControlPlugin extends BasePlugin {
static id = 'TreeControlPlugin';
// 关联渲染器名字
rendererName = 'input-tree';
$schema = '/schemas/TreeControlSchema.json';

Some files were not shown because too many files have changed in this diff Show More