mirror of
https://gitee.com/baidu/amis.git
synced 2024-12-02 03:48:13 +08:00
Merge branch 'master' into fix-date-defaultValue
This commit is contained in:
commit
b292a66c42
@ -958,11 +958,17 @@ Cards 模式支持 [Cards](./cards) 中的所有功能。
|
||||
|
||||
可以在列上配置`"sortable": true`,该列表头右侧会渲染一个可点击的排序图标,可以切换`正序`和`倒序`。
|
||||
|
||||
> 如果想默认就基于某个字段排序,可以结合 `defaultParams` 一起配置。
|
||||
|
||||
```schema: scope="body"
|
||||
{
|
||||
"type": "crud",
|
||||
"syncLocation": false,
|
||||
"api": "/api/mock2/sample",
|
||||
"defaultParams": {
|
||||
"orderBy": "engine",
|
||||
"orderDir": "desc"
|
||||
},
|
||||
"columns": [
|
||||
{
|
||||
"name": "id",
|
||||
@ -1074,7 +1080,7 @@ amis 只负责生成下拉选择器组件,并将搜索参数传递给接口,
|
||||
|
||||
#### 下拉数据源
|
||||
|
||||
过滤器的数据域支持API接口和上下文数据(`3.6.0`及以上版本)
|
||||
过滤器的数据域支持 API 接口和上下文数据(`3.6.0`及以上版本)
|
||||
|
||||
```schema
|
||||
{
|
||||
@ -3378,7 +3384,7 @@ itemAction 里的 onClick 还能通过 `data` 参数拿到当前行的数据,
|
||||
除了 Table 组件默认支持的列配置,CRUD 的列配置还额外支持以下属性:
|
||||
|
||||
| 属性名 | 类型 | 默认值 | 说明 | 版本 |
|
||||
| ------------------ | --------------------------------------------------------------- | ------- | --------------------------------------------------------------------------- | --- |
|
||||
| ------------------ | --------------------------------------------------------------- | ------- | --------------------------------------------------------------------------- | ---- |
|
||||
| sortable | `boolean` | `false` | 是否可排序 |
|
||||
| searchable | `boolean` \| `Schema` | `false` | 是否可快速搜索,开启`autoGenerateFilter`后,`searchable`支持配置`Schema` |
|
||||
| filterable | `boolean` \| [`QuickFilterConfig`](./crud.md#quickfilterconfig) | `false` | 是否可快速搜索,`options`属性为静态选项,支持设置`source`属性从接口获取选项 |
|
||||
@ -3388,7 +3394,7 @@ itemAction 里的 onClick 还能通过 `data` 参数拿到当前行的数据,
|
||||
#### QuickFilterConfig
|
||||
|
||||
| 属性名 | 类型 | 默认值 | 说明 | 版本 |
|
||||
| ------------- | ----------------------------- | ------- | -------------------------------------------------------- | ------- |
|
||||
| ------------- | ----------------------------------------- | ------- | -------------------------------------------------------- | --------------------------- |
|
||||
| options | `Array<any>` | - | 静态选项 | |
|
||||
| multiple | `boolean` | `false` | 是否支持多选 | |
|
||||
| source | [`Api`](../../docs/types/api) \| `string` | - | 选项 API 接口 | `3.6.0`版本后支持上下文变量 |
|
||||
@ -4948,7 +4954,7 @@ value 结构说明:
|
||||
|
||||
#### 行记录中字段赋值
|
||||
|
||||
需要通过表达式配置动态`name`或`id`和`componentName`或`componentId`。例如修改`engine`选中状态的同时选中`version`,勾选`id`的同时去掉对`engine`的选中。
|
||||
需要通过表达式配置动态`id`和`componentId`。例如修改`engine`选中状态的同时选中`version`,勾选`id`的同时去掉对`engine`的选中。
|
||||
|
||||
```schema: scope="body"
|
||||
{
|
||||
@ -4960,13 +4966,12 @@ value 结构说明:
|
||||
{
|
||||
"name": "id",
|
||||
"label": "ID",
|
||||
"id": "u:3db3f2b1b99e",
|
||||
"onEvent": {
|
||||
"click": {
|
||||
"actions": [
|
||||
{
|
||||
"actionType": "setValue",
|
||||
"componentId": "u:4868d7db0139_${index}",
|
||||
"componentId": "version_${index}",
|
||||
"args": {
|
||||
"value": false
|
||||
}
|
||||
@ -4981,13 +4986,12 @@ value 结构说明:
|
||||
"label": "engine",
|
||||
"quickEdit": true,
|
||||
"quickEditEnabledOn": "this.id < 5",
|
||||
"id": "u:0b9be99f3403",
|
||||
"onEvent": {
|
||||
"change": {
|
||||
"actions": [
|
||||
{
|
||||
"actionType": "setValue",
|
||||
"componentName": "version_${index}",
|
||||
"componentId": "version_${index}",
|
||||
"args": {
|
||||
"value": true
|
||||
}
|
||||
@ -4997,12 +5001,12 @@ value 结构说明:
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "version_${index}",
|
||||
"name": "version",
|
||||
"type": "checkbox",
|
||||
"label": "version",
|
||||
"quickEdit": true,
|
||||
"quickEditEnabledOn": "this.id < 5",
|
||||
"id": "u:4868d7db0139_${index}"
|
||||
"id": "version_${index}"
|
||||
}
|
||||
],
|
||||
"id": "u:f5bad706d7c5"
|
||||
|
@ -1901,6 +1901,7 @@ order: 54
|
||||
{
|
||||
"type": "button",
|
||||
"label": "新增一行(未指定添加位置)",
|
||||
"className": "mr-2",
|
||||
"onEvent": {
|
||||
"click": {
|
||||
"actions": [
|
||||
@ -1985,6 +1986,7 @@ order: 54
|
||||
{
|
||||
"type": "button",
|
||||
"label": "删除行(指定行号)",
|
||||
"className": "mr-2",
|
||||
"onEvent": {
|
||||
"click": {
|
||||
"actions": [
|
||||
@ -2184,6 +2186,7 @@ order: 54
|
||||
{
|
||||
"type": "button",
|
||||
"label": "更新index为1和3的行记录",
|
||||
"className": "mr-2",
|
||||
"onEvent": {
|
||||
"click": {
|
||||
"actions": [
|
||||
@ -2205,6 +2208,7 @@ order: 54
|
||||
{
|
||||
"type": "button",
|
||||
"label": "更新a=a3的行记录",
|
||||
"className": "mr-2",
|
||||
"onEvent": {
|
||||
"click": {
|
||||
"actions": [
|
||||
@ -2315,6 +2319,74 @@ order: 54
|
||||
}
|
||||
```
|
||||
|
||||
#### 行记录内表单项联动
|
||||
|
||||
需要通过表达式配置动态 `id` 和 `componentId`。
|
||||
|
||||
```schema: scope="body"
|
||||
{
|
||||
"type": "form",
|
||||
"api": "/api/mock2/form/saveForm",
|
||||
"body": [
|
||||
{
|
||||
"type": "input-table",
|
||||
"label": "表格表单",
|
||||
"id": "setValue-input-table",
|
||||
"name": "table",
|
||||
"columns": [
|
||||
{
|
||||
"type": "input-number",
|
||||
"name": "num1",
|
||||
"label": "数量",
|
||||
"onEvent": {
|
||||
"change": {
|
||||
"actions": [
|
||||
{
|
||||
"actionType": "setValue",
|
||||
"componentId": "num2_${index}",
|
||||
"args": {
|
||||
"value": "${num1 * 10}"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "num2",
|
||||
"id": "num2_${index}",
|
||||
"label": "金额"
|
||||
}
|
||||
],
|
||||
"addable": true,
|
||||
"footerAddBtn": {
|
||||
"label": "新增",
|
||||
"icon": "fa fa-plus",
|
||||
"hidden": true
|
||||
},
|
||||
"strictMode": true,
|
||||
"minLength": 0,
|
||||
"needConfirm": false,
|
||||
"showTableAddBtn": false
|
||||
}
|
||||
],
|
||||
"data": {
|
||||
"table": [
|
||||
{
|
||||
"id": 1,
|
||||
"num1": 1,
|
||||
"num2": "10"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"num1": "2",
|
||||
"num2": 20
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### clear
|
||||
|
||||
```schema: scope="body"
|
||||
|
@ -61,4 +61,6 @@ order: 30
|
||||
| ak | `string` | 无 | 百度/高德地图的 ak |
|
||||
| clearable | `boolean` | false | 输入框是否可清空 |
|
||||
| placeholder | `string` | '请选择位置' | 默认提示 |
|
||||
| autoSelectCurrentLoc | `boolean` | false | 是否自动选中当前地理位置 |
|
||||
| onlySelectCurrentLoc | `boolean` | false | 是否限制只能选中当前地理位置,设置为true后,可用于充当定位组件 |
|
||||
| coordinatesType | `string` | 'bd09' | 默为百度/高德坐标,可设置为'gcj02', 高德地图不支持坐标转换 |
|
||||
|
@ -25,6 +25,24 @@ order: 51
|
||||
}
|
||||
```
|
||||
|
||||
## 禁用状态
|
||||
|
||||
```schema: scope="body"
|
||||
{
|
||||
"type": "form",
|
||||
"api": "/api/mock2/form/saveForm",
|
||||
"body": [
|
||||
{
|
||||
"name": "switch",
|
||||
"type": "switch",
|
||||
"disabled": true,
|
||||
"label": "开关",
|
||||
"option": "开关说明"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 配置真假值
|
||||
|
||||
默认情况:
|
||||
@ -105,7 +123,7 @@ order: 51
|
||||
|
||||
## 不同尺寸
|
||||
|
||||
> 2.0.0 及以上版本
|
||||
> `2.0.0` 及以上版本
|
||||
|
||||
```schema: scope="body"
|
||||
{
|
||||
@ -127,18 +145,123 @@ order: 51
|
||||
}
|
||||
```
|
||||
|
||||
## 加载状态
|
||||
|
||||
> `3.6.0` 及以上版本
|
||||
|
||||
设置`"loading": true`, 标识开关操作的异步任务仍在执行中。另外`loadingOn`支持表达式
|
||||
|
||||
```schema: scope="body"
|
||||
{
|
||||
"type": "form",
|
||||
"api": "/api/mock2/form/saveForm",
|
||||
"data": {
|
||||
"shouldLoading": true
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"type": "switch",
|
||||
"name": "switch1",
|
||||
"label": "",
|
||||
"loading": true,
|
||||
"value": true
|
||||
},
|
||||
{
|
||||
|
||||
"type": "switch",
|
||||
"name": "switch2",
|
||||
"label": "",
|
||||
"size": "sm",
|
||||
"disabled": true,
|
||||
"loading": true
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
配合`ajax`动作,实现开关操作后台异步任务:
|
||||
|
||||
```schema: scope="body"
|
||||
{
|
||||
"type": "page",
|
||||
"body": [
|
||||
{
|
||||
"type": "form",
|
||||
"id": "demo-form",
|
||||
"body": [
|
||||
{
|
||||
"type": "hidden",
|
||||
"name": "isFetching",
|
||||
"value": false
|
||||
},
|
||||
{
|
||||
"type": "switch",
|
||||
"name": "switch",
|
||||
"label": "操作状态开关",
|
||||
"mode": "horizontal",
|
||||
"loadingOn": "${isFetching}",
|
||||
"onEvent": {
|
||||
"change": {
|
||||
"actions": [
|
||||
{
|
||||
"actionType": "toast",
|
||||
"args": {
|
||||
"msgType": "warning",
|
||||
"msg": "任务${switch === true ? '派发' : '取消'}成功,等待后台操作..."
|
||||
}
|
||||
},
|
||||
{
|
||||
"actionType": "setValue",
|
||||
"componentId": "demo-form",
|
||||
"args": {
|
||||
"value": {
|
||||
"isFetching": true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"actionType": "ajax",
|
||||
"api": {
|
||||
"url": "/api/mock2/form/saveForm?waitSeconds=3",
|
||||
"method": "get",
|
||||
"messages": {
|
||||
"success": "操作成功",
|
||||
"failed": "操作失败"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"actionType": "setValue",
|
||||
"componentId": "demo-form",
|
||||
"args": {
|
||||
"value": {
|
||||
"isFetching": false
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 属性表
|
||||
|
||||
除了支持 [普通表单项属性表](./formitem#%E5%B1%9E%E6%80%A7%E8%A1%A8) 中的配置以外,还支持下面一些配置
|
||||
|
||||
| 属性名 | 类型 | 默认值 | 说明 |
|
||||
| ---------- | --------------------------- | ------- | -------------------- |
|
||||
| 属性名 | 类型 | 默认值 | 说明 | 版本 |
|
||||
| ---------- | --------------------------- | ------- | -------------------- | --- |
|
||||
| option | `string` | | 选项说明 |
|
||||
| onText | `string / IconSchema` | | 开启时开关显示的内容 |
|
||||
| offText | `string / IconSchema` | | 关闭时开关显示的内容 |
|
||||
| trueValue | `boolean / string / number` | `true` | 标识真值 |
|
||||
| falseValue | `boolean / string / number` | `false` | 标识假值 |
|
||||
| size | `"sm" \| "md"` | `"md"` | 开关大小 |
|
||||
| loading | `boolean` | `false` | 是否处于加载状态 | `3.6.0` |
|
||||
|
||||
IconSchema 配置
|
||||
| 属性名 | 类型 | 默认值 | 说明 |
|
||||
|
@ -103,3 +103,7 @@ amisScoped.updateProps({
|
||||
## CRUD api 分页功能失效
|
||||
|
||||
如果 api 地址中有变量,比如 `/api/mock2/sample/${id}`,amis 就不会自动加上分页参数,需要自己加上,改成 `/api/mock2/sample/${id}?page=${page}&perPage=${perPage}`
|
||||
|
||||
## CRUD 性能较慢怎么办?
|
||||
|
||||
3.4.1 之后版本有个 `lazyRenderAfter` 配置项,默认是 100,可以改小点,延迟渲染不在屏幕中的行
|
||||
|
@ -259,7 +259,13 @@ export function embed(
|
||||
...props,
|
||||
scopeRef: (ref: any) => {
|
||||
if (ref) {
|
||||
Object.assign(scoped, ref);
|
||||
Object.keys(ref).forEach(key => {
|
||||
let value = ref[key];
|
||||
if (typeof value === 'function') {
|
||||
value = value.bind(ref);
|
||||
}
|
||||
(scoped as any)[key] = value;
|
||||
});
|
||||
callback?.();
|
||||
}
|
||||
}
|
||||
|
@ -688,7 +688,10 @@ if (fis.project.currentMedia() === 'publish-sdk') {
|
||||
postprocessor: convertSCSSIE11
|
||||
});
|
||||
const ghPages = fis.media('gh-pages');
|
||||
ghPages.set('project.files', ['examples/index.html']);
|
||||
ghPages.set('project.files', [
|
||||
'examples/index.html',
|
||||
'/examples/static/*.docx'
|
||||
]);
|
||||
|
||||
ghPages.match('*.scss', {
|
||||
parser: fis.plugin('sass', {
|
||||
@ -1008,6 +1011,10 @@ if (fis.project.currentMedia() === 'publish-sdk') {
|
||||
useHash: true
|
||||
});
|
||||
|
||||
ghPages.match('*.docx', {
|
||||
useHash: false
|
||||
});
|
||||
|
||||
ghPages.match('*.{js,ts,tsx,jsx}', {
|
||||
optimizer: fis.plugin('terser'),
|
||||
useHash: true
|
||||
|
@ -6,5 +6,5 @@
|
||||
"packages/amis"
|
||||
],
|
||||
"useWorkspaces": false,
|
||||
"version": "3.5.1"
|
||||
"version": "3.5.3"
|
||||
}
|
||||
|
@ -45,6 +45,7 @@
|
||||
"qs": "6.9.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@fortawesome/fontawesome-free": "^6.1.1",
|
||||
"@babel/generator": "^7.22.9",
|
||||
"@babel/parser": "^7.22.7",
|
||||
"@babel/traverse": "^7.22.8",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "amis-core",
|
||||
"version": "3.5.1",
|
||||
"version": "3.5.3",
|
||||
"description": "amis-core",
|
||||
"main": "lib/index.js",
|
||||
"module": "esm/index.js",
|
||||
@ -46,7 +46,7 @@
|
||||
"esm"
|
||||
],
|
||||
"dependencies": {
|
||||
"amis-formula": "^3.5.1",
|
||||
"amis-formula": "^3.5.3",
|
||||
"classnames": "2.3.2",
|
||||
"file-saver": "^2.0.2",
|
||||
"hoist-non-react-statics": "^3.3.2",
|
||||
|
@ -474,7 +474,7 @@ export class RootRenderer extends React.Component<RootRendererProps> {
|
||||
const store = this.store;
|
||||
|
||||
if (store.runtimeError) {
|
||||
this.renderRuntimeError();
|
||||
return this.renderRuntimeError();
|
||||
}
|
||||
|
||||
return (
|
||||
|
58
packages/amis-core/src/components/ErrorBoundary.tsx
Normal file
58
packages/amis-core/src/components/ErrorBoundary.tsx
Normal file
@ -0,0 +1,58 @@
|
||||
/**
|
||||
* @file ErrorBoundary
|
||||
* @description 捕获发生在其子组件树任何位置的 JavaScript 错误,并打印这些错误
|
||||
* @author wibetter
|
||||
*/
|
||||
import React from 'react';
|
||||
|
||||
interface ErrorBoundaryProps {
|
||||
// 自定义错误信息,控制台输出
|
||||
customErrorMsg?: string;
|
||||
fallback?: () => void;
|
||||
children: any;
|
||||
}
|
||||
|
||||
interface ErrorBoundaryStates {
|
||||
hasError: boolean;
|
||||
}
|
||||
|
||||
export default class ErrorBoundary extends React.Component<
|
||||
ErrorBoundaryProps,
|
||||
ErrorBoundaryStates
|
||||
> {
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
this.state = {hasError: false};
|
||||
}
|
||||
|
||||
componentDidCatch(error: any, errorInfo: any) {
|
||||
const {customErrorMsg} = this.props;
|
||||
if (customErrorMsg) {
|
||||
console.warn(customErrorMsg);
|
||||
}
|
||||
|
||||
console.warn('错误对象:', error);
|
||||
console.warn('错误信息:', errorInfo);
|
||||
this.setState({
|
||||
hasError: true
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const {fallback} = this.props;
|
||||
if (this.state.hasError) {
|
||||
if (fallback) {
|
||||
return fallback();
|
||||
}
|
||||
|
||||
// 默认渲染错误信息
|
||||
return (
|
||||
<div className="renderer-error-boundary">
|
||||
渲染发生错误,详细错误信息请查看控制台输出。
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
@ -96,6 +96,7 @@ import type {FilterContext} from 'amis-formula';
|
||||
import LazyComponent from './components/LazyComponent';
|
||||
import Overlay from './components/Overlay';
|
||||
import PopOver from './components/PopOver';
|
||||
import ErrorBoundary from './components/ErrorBoundary';
|
||||
import {FormRenderer} from './renderers/Form';
|
||||
import type {FormHorizontal, FormSchemaBase} from './renderers/Form';
|
||||
import {
|
||||
@ -182,6 +183,7 @@ export {
|
||||
LazyComponent,
|
||||
Overlay,
|
||||
PopOver,
|
||||
ErrorBoundary,
|
||||
addSchemaFilter,
|
||||
OptionsControlProps,
|
||||
FormOptionsControl,
|
||||
|
@ -522,6 +522,18 @@ export default class Form extends React.Component<FormProps, object> {
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// withStore 里面与上层数据会做同步
|
||||
// 这个时候变更的数据没有同步 onChange 出去,出现数据不一致的问题。
|
||||
// https://github.com/baidu/amis/issues/8773
|
||||
this.toDispose.push(
|
||||
reaction(
|
||||
() => store.initedAt,
|
||||
() => {
|
||||
store.inited && this.emitChange(!!this.props.submitOnChange);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
|
@ -528,7 +528,8 @@ export const TableStore = iRendererStore
|
||||
exportExcelLoading: false,
|
||||
searchFormExpanded: false, // 用来控制搜索框是否展开了,那个自动根据 searchable 生成的表单 autoGenerateFilter
|
||||
lazyRenderAfter: 100,
|
||||
tableLayout: 'auto'
|
||||
tableLayout: 'auto',
|
||||
theadHeight: 0
|
||||
})
|
||||
.views(self => {
|
||||
function getColumnsExceptBuiltinTypes() {
|
||||
@ -1001,7 +1002,7 @@ export const TableStore = iRendererStore
|
||||
},
|
||||
|
||||
buildStyles(style: any) {
|
||||
style = {...style};
|
||||
style = {...style, '--Table-thead-height': self.theadHeight + 'px'};
|
||||
|
||||
getFilteredColumns().forEach(column => {
|
||||
style[`--Table-column-${column.index}-width`] =
|
||||
@ -1050,13 +1051,7 @@ export const TableStore = iRendererStore
|
||||
);
|
||||
}
|
||||
|
||||
if (config.multiple !== undefined) {
|
||||
self.multiple = config.multiple;
|
||||
} else {
|
||||
// 如果通过crud或picker,multiple始终设置了true或false
|
||||
// 如果仅使用table,默认multiple为true,但props未设置multiple的情况下其实是展示单选
|
||||
self.multiple = false;
|
||||
}
|
||||
config.multiple !== undefined && (self.multiple = config.multiple);
|
||||
config.footable !== undefined && (self.footable = config.footable);
|
||||
config.expandConfig !== undefined &&
|
||||
(self.expandConfig = config.expandConfig);
|
||||
@ -1301,9 +1296,9 @@ export const TableStore = iRendererStore
|
||||
if (!table) {
|
||||
return;
|
||||
}
|
||||
const cols = [].slice.call(
|
||||
table.querySelectorAll(':scope>thead>tr>th[data-index]')
|
||||
);
|
||||
const thead = table.querySelector(':scope>thead') as HTMLElement;
|
||||
const cols = [].slice.call(thead.querySelectorAll('tr>th[data-index]'));
|
||||
self.theadHeight = thead.offsetHeight;
|
||||
cols.forEach((col: HTMLElement) => {
|
||||
const index = parseInt(col.getAttribute('data-index')!, 10);
|
||||
const column = self.columns[index];
|
||||
|
@ -1,7 +1,7 @@
|
||||
// https://json-schema.org/draft-07/json-schema-release-notes.html
|
||||
import type {JSONSchema7} from 'json-schema';
|
||||
import {ListenerAction} from './actions/Action';
|
||||
import {debounceConfig} from './utils/renderer-event';
|
||||
import {debounceConfig, trackConfig} from './utils/renderer-event';
|
||||
|
||||
export interface Option {
|
||||
/**
|
||||
@ -458,7 +458,8 @@ export interface EventTrack {
|
||||
| 'tabChange'
|
||||
| 'pageLoaded'
|
||||
| 'pageHidden'
|
||||
| 'pageVisible';
|
||||
| 'pageVisible'
|
||||
| string;
|
||||
|
||||
/**
|
||||
* 事件数据
|
||||
@ -618,6 +619,7 @@ export interface BaseSchemaWithoutType {
|
||||
weight?: number; // 权重
|
||||
actions: ListenerAction[]; // 执行的动作集
|
||||
debounce?: debounceConfig;
|
||||
track?: trackConfig;
|
||||
};
|
||||
};
|
||||
/**
|
||||
|
@ -33,6 +33,8 @@ export function attachmentAdpator(
|
||||
// 很可能是中文被 url-encode 了
|
||||
if (filename && filename.replace(/[^%]/g, '').length > 2) {
|
||||
filename = decodeURIComponent(filename);
|
||||
// 有些后端用错了,导致空格转义成了 +,这里转回来
|
||||
filename = filename.replace(/\+/g, ' ');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,10 +10,16 @@ export interface debounceConfig {
|
||||
leading?: boolean;
|
||||
trailing?: boolean;
|
||||
}
|
||||
|
||||
export interface trackConfig {
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
// 事件监听器
|
||||
export interface EventListeners {
|
||||
[propName: string]: {
|
||||
debounce?: debounceConfig;
|
||||
track?: trackConfig;
|
||||
weight?: number; // 权重
|
||||
actions: ListenerAction[]; // 执行的动作集
|
||||
};
|
||||
@ -26,6 +32,7 @@ export interface OnEventProps {
|
||||
weight?: number; // 权重
|
||||
actions: ListenerAction[]; // 执行的动作集,
|
||||
debounce?: debounceConfig;
|
||||
track?: trackConfig;
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -36,6 +43,7 @@ export interface RendererEventListener {
|
||||
type: string;
|
||||
weight: number;
|
||||
debounce: debounceConfig | null;
|
||||
track: trackConfig | null;
|
||||
actions: ListenerAction[];
|
||||
executing?: boolean;
|
||||
debounceInstance?: any;
|
||||
@ -118,6 +126,7 @@ export const bindEvent = (renderer: any) => {
|
||||
renderer,
|
||||
type: key,
|
||||
debounce: listener.debounce || null,
|
||||
track: listeners[key].track || null,
|
||||
weight: listener.weight || 0,
|
||||
actions: listener.actions
|
||||
});
|
||||
@ -127,6 +136,7 @@ export const bindEvent = (renderer: any) => {
|
||||
renderer,
|
||||
type: key,
|
||||
debounce: listeners[key].debounce || null,
|
||||
track: listeners[key].track || null,
|
||||
weight: listeners[key].weight || 0,
|
||||
actions: listeners[key].actions
|
||||
});
|
||||
@ -245,6 +255,17 @@ export async function dispatchEvent(
|
||||
checkExecuted();
|
||||
}
|
||||
|
||||
if (listener?.track) {
|
||||
const {id: trackId, name: trackName} = listener.track;
|
||||
renderer?.props?.env?.tracker({
|
||||
eventType: listener.type,
|
||||
eventData: {
|
||||
trackId,
|
||||
trackName
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 停止后续监听器执行
|
||||
if (rendererEvent.stoped) {
|
||||
break;
|
||||
|
@ -59,7 +59,7 @@
|
||||
"sortablejs": "^1.14.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@fortawesome/fontawesome-free": "^5.15.3",
|
||||
"@fortawesome/fontawesome-free": "^6.1.1",
|
||||
"@rollup/plugin-commonjs": "^22.0.0",
|
||||
"@rollup/plugin-json": "^4.1.0",
|
||||
"@rollup/plugin-node-resolve": "^13.3.0",
|
||||
|
@ -801,14 +801,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.ae-Editor-renderer-error {
|
||||
padding: 5px;
|
||||
font-family: PingFangSC-Medium;
|
||||
font-size: 14px;
|
||||
color: #cf1322;
|
||||
border: 1px dashed #cf1322;
|
||||
}
|
||||
|
||||
.ae-Editor-tip {
|
||||
user-select: none;
|
||||
max-width: 100px;
|
||||
|
@ -23,7 +23,8 @@ import {
|
||||
JSONUpdate,
|
||||
getFixDialogType
|
||||
} from '../util';
|
||||
import {createObject, createObjectFromChain} from 'amis-core';
|
||||
import {createObjectFromChain} from 'amis-core';
|
||||
import {ErrorBoundary} from 'amis-core';
|
||||
import {CommonConfigWrapper} from './CommonConfigWrapper';
|
||||
import type {Schema} from 'amis';
|
||||
import type {DataScope} from 'amis-core';
|
||||
@ -40,14 +41,11 @@ export function makeWrapper(
|
||||
type Props = RendererProps & {
|
||||
$$id: string;
|
||||
};
|
||||
type States = {
|
||||
hasError: boolean;
|
||||
};
|
||||
const store = manager.store;
|
||||
const renderer = rendererConfig.component;
|
||||
|
||||
@observer
|
||||
class Wrapper extends React.Component<Props, States> {
|
||||
class Wrapper extends React.Component<Props> {
|
||||
static displayName = renderer.displayName;
|
||||
static propsList = ((renderer && renderer.propsList) || []).concat([
|
||||
'$$id'
|
||||
@ -57,11 +55,6 @@ export function makeWrapper(
|
||||
editorNode?: EditorNodeType;
|
||||
scopeId?: string;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {hasError: false};
|
||||
}
|
||||
|
||||
UNSAFE_componentWillMount() {
|
||||
const parent: EditorNodeType = (this.context as any) || store.root;
|
||||
if (!info.id) {
|
||||
@ -133,16 +126,6 @@ export function makeWrapper(
|
||||
}
|
||||
}
|
||||
|
||||
componentDidCatch(error: any, errorInfo: any) {
|
||||
console.warn(`${info.name}(${info.id})渲染发生错误:`);
|
||||
console.warn('当前渲染器信息:', info);
|
||||
console.warn('错误对象:', error);
|
||||
console.warn('错误信息:', errorInfo);
|
||||
this.setState({
|
||||
hasError: true
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.editorNode && isAlive(this.editorNode)) {
|
||||
const parent: EditorNodeType = (this.context as any) || store.root;
|
||||
@ -186,14 +169,6 @@ export function makeWrapper(
|
||||
render() {
|
||||
const {$$id, ...rest} = this.props;
|
||||
|
||||
if (this.state.hasError) {
|
||||
return (
|
||||
<div className="ae-Editor-renderer-error">
|
||||
{info.name}({info.id})渲染发生错误,详细错误信息请查看控制台输出。
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* 根据渲染器信息决定时 NodeWrapper 包裹还是 ContainerWrapper 包裹。
|
||||
* NodeWrapper 主要完成 dom 节点的标记(即:添加 data-editor-id 属性)。
|
||||
@ -207,10 +182,22 @@ export function makeWrapper(
|
||||
: info.regions
|
||||
? ContainerWrapper
|
||||
: NodeWrapper; /*)*/
|
||||
|
||||
return (
|
||||
<EditorNodeContext.Provider
|
||||
value={this.editorNode || (this.context as any)}
|
||||
>
|
||||
<ErrorBoundary
|
||||
customErrorMsg={`拦截到${
|
||||
info.type
|
||||
}渲染错误,当前组件信息: ${JSON.stringify(this.props.$schema)}`}
|
||||
fallback={() => {
|
||||
return (
|
||||
<div className="renderer-error-boundary">
|
||||
{info?.type}
|
||||
渲染发生错误,详细错误信息请查看控制台输出。
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
>
|
||||
<Wrapper
|
||||
{...rest}
|
||||
@ -219,6 +206,7 @@ export function makeWrapper(
|
||||
$$node={this.editorNode}
|
||||
ref={this.wrapperRef}
|
||||
/>
|
||||
</ErrorBoundary>
|
||||
</EditorNodeContext.Provider>
|
||||
);
|
||||
}
|
||||
|
@ -49,7 +49,7 @@
|
||||
"mobx-state-tree": "^3.17.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@fortawesome/fontawesome-free": "^5.15.3",
|
||||
"@fortawesome/fontawesome-free": "^6.1.1",
|
||||
"@rollup/plugin-commonjs": "^22.0.0",
|
||||
"@rollup/plugin-json": "^4.1.0",
|
||||
"@rollup/plugin-node-resolve": "^13.3.0",
|
||||
|
@ -45,7 +45,7 @@ export class CRUDCardsPlugin extends BaseCRUDPlugin {
|
||||
|
||||
$schema = '/schemas/CRUD2CardsSchema.json';
|
||||
|
||||
docLink = '/amis/zh-CN/components/crud2';
|
||||
docLink = '/amis/zh-CN/components/cards';
|
||||
|
||||
previewSchema: Record<string, any> = this.generatePreviewSchema('cards');
|
||||
|
||||
|
@ -45,7 +45,7 @@ export class CRUDListPlugin extends BaseCRUDPlugin {
|
||||
|
||||
$schema = '/schemas/CRUD2ListSchema.json';
|
||||
|
||||
docLink = '/amis/zh-CN/components/crud2';
|
||||
docLink = '/amis/zh-CN/components/list';
|
||||
|
||||
previewSchema: Record<string, any> = this.generatePreviewSchema('list');
|
||||
|
||||
|
@ -38,7 +38,7 @@ export class CRUDTablePlugin extends BaseCRUDPlugin {
|
||||
|
||||
$schema = '/schemas/CRUD2TableSchema.json';
|
||||
|
||||
docLink = '/amis/zh-CN/components/crud2';
|
||||
docLink = '/amis/zh-CN/components/table2';
|
||||
|
||||
previewSchema: Record<string, any> = this.generatePreviewSchema('table2');
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {EditorNodeType, getSchemaTpl} from 'amis-editor-core';
|
||||
import {EditorNodeType, getSchemaTpl, tipedLabel} from 'amis-editor-core';
|
||||
import {registerEditorPlugin} from 'amis-editor-core';
|
||||
import {BasePlugin, BaseEventContext} from 'amis-editor-core';
|
||||
import {ValidatorTag} from '../../validator';
|
||||
@ -82,11 +82,30 @@ export class LocationControlPlugin extends BasePlugin {
|
||||
{label: '国测局坐标', value: 'gcj02'}
|
||||
]
|
||||
},
|
||||
|
||||
getSchemaTpl('switch', {
|
||||
name: 'autoSelectCurrentLoc',
|
||||
label: tipedLabel(
|
||||
'自动选择',
|
||||
'开启后,自动选中用户当前的地理位置'
|
||||
)
|
||||
}),
|
||||
getSchemaTpl('switch', {
|
||||
name: 'onlySelectCurrentLoc',
|
||||
label: tipedLabel(
|
||||
'只读模式',
|
||||
'开启后,只能使用当前地理位置,不可选择其他地理位置'
|
||||
)
|
||||
}),
|
||||
getSchemaTpl('clearable'),
|
||||
getSchemaTpl('labelRemark'),
|
||||
getSchemaTpl('remark'),
|
||||
getSchemaTpl('placeholder'),
|
||||
getSchemaTpl('placeholder', {
|
||||
visibleOn: '!onlySelectCurrentLoc'
|
||||
}),
|
||||
getSchemaTpl('placeholder', {
|
||||
name: 'getLocationPlaceholder',
|
||||
visibleOn: 'onlySelectCurrentLoc'
|
||||
}),
|
||||
getSchemaTpl('description')
|
||||
]
|
||||
},
|
||||
|
@ -249,6 +249,11 @@ export class TreeSelectControlPlugin extends BasePlugin {
|
||||
actionType: 'setValue',
|
||||
actionLabel: '赋值',
|
||||
description: '触发组件数据更新'
|
||||
},
|
||||
{
|
||||
actionType: 'reload',
|
||||
actionLabel: '重新加载',
|
||||
description: '触发组件数据刷新并重新渲染'
|
||||
}
|
||||
];
|
||||
|
||||
|
@ -78,6 +78,11 @@ interface EventDialogData {
|
||||
open: boolean;
|
||||
wait?: number;
|
||||
};
|
||||
trackConfig?: {
|
||||
open: boolean;
|
||||
id: string;
|
||||
name: string;
|
||||
};
|
||||
[propName: string]: any;
|
||||
}
|
||||
|
||||
@ -235,6 +240,16 @@ export class EventControl extends React.Component<
|
||||
...eventInfo.debounce
|
||||
};
|
||||
}
|
||||
if (!eventInfo.track) {
|
||||
eventInfo.track = {
|
||||
open: false
|
||||
};
|
||||
} else {
|
||||
eventInfo.track = {
|
||||
open: true,
|
||||
...eventInfo.track
|
||||
};
|
||||
}
|
||||
this.setState({
|
||||
eventDialogData: eventInfo,
|
||||
showEventDialog: true
|
||||
@ -243,11 +258,11 @@ export class EventControl extends React.Component<
|
||||
|
||||
eventDialogSubmit(formData: any) {
|
||||
const {onChange} = this.props;
|
||||
const {eventName, debounce = {}} = formData;
|
||||
const {eventName, debounce = {}, track = {}} = formData;
|
||||
let onEvent = {
|
||||
...this.state.onEvent
|
||||
};
|
||||
let eventConfig = onEvent[`${eventName}`];
|
||||
let eventConfig = {...onEvent[`${eventName}`]};
|
||||
if (!debounce.open) {
|
||||
delete eventConfig.debounce;
|
||||
} else {
|
||||
@ -258,6 +273,18 @@ export class EventControl extends React.Component<
|
||||
}
|
||||
};
|
||||
}
|
||||
if (!track.open) {
|
||||
delete eventConfig.track;
|
||||
} else {
|
||||
eventConfig = {
|
||||
...eventConfig,
|
||||
track: {
|
||||
id: track.id,
|
||||
name: track.name
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
onEvent[`${eventName}`] = {
|
||||
...eventConfig
|
||||
};
|
||||
@ -1256,6 +1283,27 @@ export class EventControl extends React.Component<
|
||||
max: 10000,
|
||||
min: 0,
|
||||
type: 'input-number'
|
||||
},
|
||||
{
|
||||
label: '事件埋点',
|
||||
type: 'switch',
|
||||
name: 'track.open',
|
||||
description:
|
||||
'开启事件埋点后,每次事件触发都会发送埋点数据到后台'
|
||||
},
|
||||
{
|
||||
label: 'track-id',
|
||||
required: true,
|
||||
hiddenOn: '!track.open',
|
||||
name: 'track.id',
|
||||
type: 'input-text'
|
||||
},
|
||||
{
|
||||
label: 'track-name',
|
||||
required: true,
|
||||
hiddenOn: '!track.open',
|
||||
name: 'track.name',
|
||||
type: 'input-text'
|
||||
}
|
||||
],
|
||||
onSubmit: this.eventDialogSubmit.bind(this)
|
||||
|
@ -13,6 +13,10 @@ export interface ActionEventConfig {
|
||||
debounce?: {
|
||||
wait: number;
|
||||
};
|
||||
track?: {
|
||||
id: string;
|
||||
name: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "amis-formula",
|
||||
"version": "3.5.1",
|
||||
"version": "3.5.3",
|
||||
"description": "负责 amis 里面的表达式实现,内置公式,编辑器等",
|
||||
"main": "lib/index.js",
|
||||
"module": "esm/index.js",
|
||||
|
@ -3,7 +3,7 @@
|
||||
"main": "lib/index.js",
|
||||
"module": "esm/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
"version": "3.5.1",
|
||||
"version": "3.5.3",
|
||||
"description": "",
|
||||
"scripts": {
|
||||
"build": "npm run clean-dist && NODE_ENV=production rollup -c ",
|
||||
@ -36,8 +36,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@rc-component/mini-decimal": "^1.0.1",
|
||||
"amis-core": "^3.5.1",
|
||||
"amis-formula": "^3.5.1",
|
||||
"amis-core": "^3.5.3",
|
||||
"amis-formula": "^3.5.3",
|
||||
"classnames": "2.3.2",
|
||||
"codemirror": "^5.63.0",
|
||||
"downshift": "6.1.12",
|
||||
|
@ -1972,6 +1972,9 @@
|
||||
--Switch-checked-bgColor: var(--switch-default-on-bg-color);
|
||||
--Switch-checked-onHover-bgColor: var(--switch-default-on-hover-bg-color);
|
||||
--Switch-checked-onActive-bgColor: var(--colors-brand-4);
|
||||
--Switch-spinner-icon-width: var(--sizes-base-7);
|
||||
--Switch-spinner-icon-width--sm: var(--sizes-base-5);
|
||||
--switch-spinner-left--sm: var(--sizes-size-0);
|
||||
|
||||
--collapse-default-top-border-color: var(--colors-neutral-line-8);
|
||||
--collapse-default-top-border-width: var(--borders-width-2);
|
||||
@ -3292,7 +3295,6 @@
|
||||
--spinner-size-size: var(--sizes-base-16);
|
||||
--spinner-lg-size: var(--sizes-base-24);
|
||||
--spinner-overlay-bg: var(--colors-neutral-fill-11);
|
||||
--spinner-color: var(--colors-brand-5);
|
||||
|
||||
--Spinner--lg-height: var(--spinner-lg-size);
|
||||
--Spinner--lg-width: var(--spinner-lg-size);
|
||||
@ -3304,6 +3306,7 @@
|
||||
--Spinner-overlay-bg: rgba(255, 255, 255, 0.4);
|
||||
--Spinner-width: var(--spinner-size-size);
|
||||
--Spinner-color: var(--spinner-base-color);
|
||||
--Spinner-color--disabled: rgba(0, 0, 0, 0.65);
|
||||
|
||||
// Image
|
||||
--image-image-normal-paddingTop: var(--sizes-size-3);
|
||||
|
@ -9,3 +9,11 @@
|
||||
.visibility-sensor {
|
||||
min-height: 5px;
|
||||
}
|
||||
|
||||
.renderer-error-boundary {
|
||||
padding: 5px;
|
||||
font-family: PingFangSC-Medium;
|
||||
font-size: 14px;
|
||||
color: #cf1322;
|
||||
border: 1px dashed #cf1322;
|
||||
}
|
||||
|
@ -77,6 +77,15 @@
|
||||
height: auto;
|
||||
}
|
||||
|
||||
&.#{$ns}Spinner-icon--disabled > svg.icon {
|
||||
color: var(--Spinner-color--disabled);
|
||||
fill: var(--Spinner-color--disabled);
|
||||
|
||||
& path {
|
||||
fill: var(--Spinner-color--disabled);
|
||||
}
|
||||
}
|
||||
|
||||
&--lg {
|
||||
width: var(--Spinner--lg-width);
|
||||
height: var(--Spinner--lg-height);
|
||||
|
@ -273,8 +273,12 @@
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
&--affixHeader > thead {
|
||||
visibility: collapse;
|
||||
&--affixHeader {
|
||||
margin-top: calc(var(--Table-thead-height) * -1);
|
||||
|
||||
> thead {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
&--withCombine {
|
||||
|
@ -153,6 +153,44 @@
|
||||
border-radius: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
&-spinner {
|
||||
position: absolute;
|
||||
top: var(--Switch-slider-margin);
|
||||
bottom: var(--Switch-slider-margin);
|
||||
left: var(--Switch-slider-margin);
|
||||
|
||||
& > &-icon > svg.icon {
|
||||
width: var(--Switch-spinner-icon-width);
|
||||
height: var(--Switch-spinner-icon-width);
|
||||
}
|
||||
|
||||
&--sm {
|
||||
position: absolute;
|
||||
top: var(--switch-size-sm-slider-margin);
|
||||
bottom: var(--switch-size-sm-slider-margin);
|
||||
left: var(--switch-spinner-left--sm);
|
||||
|
||||
& > .#{$ns}Switch-spinner-icon > svg.icon {
|
||||
width: var(--Switch-spinner-icon-width--sm);
|
||||
height: var(--Switch-spinner-icon-width--sm);
|
||||
}
|
||||
}
|
||||
|
||||
&.#{$ns}Switch-spinner--checked {
|
||||
left: calc(
|
||||
100% - var(--Switch-slider-width) - var(--Switch-slider-margin)
|
||||
);
|
||||
right: var(--Switch-slider-margin);
|
||||
|
||||
&.#{$ns}Switch-spinner--sm {
|
||||
left: calc(
|
||||
100% - var(--Switch-slider-width--sm) - var(--Switch-slider-margin)
|
||||
);
|
||||
right: var(--Switch-slider-margin);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.#{$ns}Switch-option {
|
||||
|
@ -109,9 +109,11 @@ $ns: 'a-';
|
||||
--colors-neutral-line-9: #f3f2f5;
|
||||
--colors-neutral-line-10: #f8f7fa;
|
||||
--colors-neutral-line-11: #ffffff;
|
||||
--fonts-base-family: -apple-system, BlinkMacSystemFont, SF Pro SC, SF Pro Text,
|
||||
Helvetica Neue, Helvetica, PingFang SC, Segoe UI, Roboto, Hiragino Sans GB,
|
||||
Arial, microsoft yahei ui, Microsoft YaHei, SimSun, sans-serif;
|
||||
--fonts-base-family: -apple-system, 'Noto Sans', 'Helvetica Neue', Helvetica,
|
||||
'Nimbus Sans L', Arial, 'Liberation Sans', 'PingFang SC', 'Hiragino Sans GB',
|
||||
'Noto Sans CJK SC', 'Source Han Sans SC', 'Source Han Sans CN',
|
||||
'Microsoft YaHei', 'Wenquanyi Micro Hei', 'WenQuanYi Zen Hei', 'ST Heiti',
|
||||
SimHei, 'WenQuanYi Zen Hei Sharp', sans-serif;
|
||||
--fonts-size-1: 48px;
|
||||
--fonts-size-2: 40px;
|
||||
--fonts-size-3: 32px;
|
||||
|
@ -109,9 +109,11 @@ $ns: 'antd-';
|
||||
--colors-neutral-line-9: #f2f4f5;
|
||||
--colors-neutral-line-10: #f7f9fa;
|
||||
--colors-neutral-line-11: #ffffff;
|
||||
--fonts-base-family: -apple-system, BlinkMacSystemFont, SF Pro SC, SF Pro Text,
|
||||
Helvetica Neue, Helvetica, PingFang SC, Segoe UI, Roboto, Hiragino Sans GB,
|
||||
Arial, microsoft yahei ui, Microsoft YaHei, SimSun, sans-serif;
|
||||
--fonts-base-family: -apple-system, 'Noto Sans', 'Helvetica Neue', Helvetica,
|
||||
'Nimbus Sans L', Arial, 'Liberation Sans', 'PingFang SC', 'Hiragino Sans GB',
|
||||
'Noto Sans CJK SC', 'Source Han Sans SC', 'Source Han Sans CN',
|
||||
'Microsoft YaHei', 'Wenquanyi Micro Hei', 'WenQuanYi Zen Hei', 'ST Heiti',
|
||||
SimHei, 'WenQuanYi Zen Hei Sharp', sans-serif;
|
||||
--fonts-size-1: 48px;
|
||||
--fonts-size-2: 40px;
|
||||
--fonts-size-3: 32px;
|
||||
|
@ -106,9 +106,12 @@ $ns: 'cxd-';
|
||||
--colors-neutral-line-9: #f2f3f5;
|
||||
--colors-neutral-line-10: #f7f8fa;
|
||||
--colors-neutral-line-11: #ffffff;
|
||||
--fonts-base-family: -apple-system, BlinkMacSystemFont, SF Pro SC, SF Pro Text,
|
||||
Helvetica Neue, Helvetica, PingFang SC, Segoe UI, Roboto, Hiragino Sans GB,
|
||||
Arial, microsoft yahei ui, Microsoft YaHei, SimSun, sans-serif;
|
||||
// 参考 https://zenozeng.github.io/fonts.css/
|
||||
--fonts-base-family: -apple-system, 'Noto Sans', 'Helvetica Neue', Helvetica,
|
||||
'Nimbus Sans L', Arial, 'Liberation Sans', 'PingFang SC', 'Hiragino Sans GB',
|
||||
'Noto Sans CJK SC', 'Source Han Sans SC', 'Source Han Sans CN',
|
||||
'Microsoft YaHei', 'Wenquanyi Micro Hei', 'WenQuanYi Zen Hei', 'ST Heiti',
|
||||
SimHei, 'WenQuanYi Zen Hei Sharp', sans-serif;
|
||||
--fonts-size-1: 48px;
|
||||
--fonts-size-2: 40px;
|
||||
--fonts-size-3: 32px;
|
||||
|
@ -117,9 +117,11 @@ $ns: 'dark-';
|
||||
--colors-neutral-line-9: #f2f4f5;
|
||||
--colors-neutral-line-10: #f7f9fa;
|
||||
--colors-neutral-line-11: #ffffff;
|
||||
--fonts-base-family: -apple-system, BlinkMacSystemFont, SF Pro SC, SF Pro Text,
|
||||
Helvetica Neue, Helvetica, PingFang SC, Segoe UI, Roboto, Hiragino Sans GB,
|
||||
Arial, microsoft yahei ui, Microsoft YaHei, SimSun, sans-serif;
|
||||
--fonts-base-family: -apple-system, 'Noto Sans', 'Helvetica Neue', Helvetica,
|
||||
'Nimbus Sans L', Arial, 'Liberation Sans', 'PingFang SC', 'Hiragino Sans GB',
|
||||
'Noto Sans CJK SC', 'Source Han Sans SC', 'Source Han Sans CN',
|
||||
'Microsoft YaHei', 'Wenquanyi Micro Hei', 'WenQuanYi Zen Hei', 'ST Heiti',
|
||||
SimHei, 'WenQuanYi Zen Hei Sharp', sans-serif;
|
||||
--fonts-size-1: 48px;
|
||||
--fonts-size-2: 40px;
|
||||
--fonts-size-3: 32px;
|
||||
|
@ -38,6 +38,8 @@ interface MapPickerProps {
|
||||
city?: string;
|
||||
};
|
||||
onChange?: (value: any) => void;
|
||||
autoSelectCurrentLoc?: boolean;
|
||||
onlySelectCurrentLoc?: boolean;
|
||||
}
|
||||
|
||||
interface LocationItem {
|
||||
@ -109,6 +111,7 @@ export class BaiduMapPicker extends React.Component<
|
||||
|
||||
@autobind
|
||||
async initMap() {
|
||||
const autoSelectCurrentLoc = this.props.autoSelectCurrentLoc ?? false;
|
||||
const map = new BMap.Map(this.mapRef.current, {
|
||||
enableMapClick: false
|
||||
});
|
||||
@ -137,11 +140,14 @@ export class BaiduMapPicker extends React.Component<
|
||||
|
||||
const geolocationControl = new BMap.GeolocationControl();
|
||||
geolocationControl.addEventListener('locationSuccess', (e: any) => {
|
||||
this.getLocations(e.point);
|
||||
this.getLocations(e.point, autoSelectCurrentLoc);
|
||||
});
|
||||
map.addControl(geolocationControl);
|
||||
|
||||
map.addEventListener('click', (e: any) => {
|
||||
if (this.props.onlySelectCurrentLoc) {
|
||||
return;
|
||||
}
|
||||
this.getLocations(e.point, true);
|
||||
});
|
||||
|
||||
@ -187,7 +193,8 @@ export class BaiduMapPicker extends React.Component<
|
||||
value ? this.getLocations(point) : geolocationControl.location();
|
||||
}
|
||||
|
||||
getLocations(point: any, select?: boolean) {
|
||||
@autobind
|
||||
getLocations(point: any, selectCurrentLoc?: boolean) {
|
||||
const map = this.map;
|
||||
|
||||
map.clearOverlays();
|
||||
@ -231,7 +238,7 @@ export class BaiduMapPicker extends React.Component<
|
||||
locs
|
||||
},
|
||||
() => {
|
||||
if (!select) {
|
||||
if (!selectCurrentLoc) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -318,7 +325,7 @@ export class BaiduMapPicker extends React.Component<
|
||||
});
|
||||
|
||||
var local = new BMap.LocalSearch(this.map, {
|
||||
//智能搜索
|
||||
// 智能搜索
|
||||
onSearchComplete: () => {
|
||||
const results = local.getResults();
|
||||
const poi = results.getPoi(0);
|
||||
@ -334,11 +341,13 @@ export class BaiduMapPicker extends React.Component<
|
||||
|
||||
render() {
|
||||
const {classnames: cx} = this.props;
|
||||
const onlySelectCurrentLoc = this.props.onlySelectCurrentLoc ?? false;
|
||||
const {locIndex, locs, inputValue, sugs} = this.state;
|
||||
const hasSug = Array.isArray(sugs) && sugs.length;
|
||||
|
||||
return (
|
||||
<div className={cx('MapPicker')}>
|
||||
{!onlySelectCurrentLoc && (
|
||||
<div className={cx('MapPicker-search TextControl-control')}>
|
||||
<div className={cx('TextControl-input')}>
|
||||
<input
|
||||
@ -348,6 +357,7 @@ export class BaiduMapPicker extends React.Component<
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div
|
||||
ref={this.mapRef}
|
||||
@ -361,7 +371,8 @@ export class BaiduMapPicker extends React.Component<
|
||||
invisible: hasSug
|
||||
})}
|
||||
>
|
||||
{locs.map((item, index) => (
|
||||
{!onlySelectCurrentLoc &&
|
||||
locs.map((item, index) => (
|
||||
<div
|
||||
onClick={this.handleSelect}
|
||||
key={index}
|
||||
@ -375,9 +386,21 @@ export class BaiduMapPicker extends React.Component<
|
||||
) : null}
|
||||
</div>
|
||||
))}
|
||||
{onlySelectCurrentLoc && locs.length > 0 && (
|
||||
<div
|
||||
onClick={this.handleSelect}
|
||||
key="locs-current"
|
||||
data-index={0}
|
||||
className={cx('MapPicker-item')}
|
||||
>
|
||||
<div className={cx('MapPicker-itemTitle')}>{locs[0].title}</div>
|
||||
<div className={cx('MapPicker-itemDesc')}>{locs[0].address}</div>
|
||||
{locIndex === 0 ? <Icon icon="success" className="icon" /> : null}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{hasSug ? (
|
||||
{hasSug && !onlySelectCurrentLoc ? (
|
||||
<div className={cx('MapPicker-sug')}>
|
||||
{sugs.map(item => (
|
||||
<div
|
||||
|
@ -14,6 +14,7 @@ export interface LocationProps extends ThemeProps, LocaleProps {
|
||||
vendor: 'baidu' | 'gaode' | 'tenxun';
|
||||
coordinatesType: 'bd09' | 'gcj02';
|
||||
placeholder: string;
|
||||
getLocationPlaceholder: string;
|
||||
clearable: boolean;
|
||||
ak: string;
|
||||
value?: {
|
||||
@ -27,6 +28,8 @@ export interface LocationProps extends ThemeProps, LocaleProps {
|
||||
popoverClassName?: string;
|
||||
onChange: (value: any) => void;
|
||||
popOverContainer?: any;
|
||||
autoSelectCurrentLoc?: boolean;
|
||||
onlySelectCurrentLoc?: boolean;
|
||||
}
|
||||
|
||||
export interface LocationState {
|
||||
@ -40,6 +43,7 @@ export class LocationPicker extends React.Component<
|
||||
> {
|
||||
static defaultProps = {
|
||||
placeholder: 'LocationPicker.placeholder',
|
||||
getLocationPlaceholder: 'LocationPicker.getLocation',
|
||||
clearable: false
|
||||
};
|
||||
domRef: React.RefObject<HTMLDivElement> = React.createRef();
|
||||
@ -155,12 +159,15 @@ export class LocationPicker extends React.Component<
|
||||
popoverClassName,
|
||||
disabled,
|
||||
placeholder,
|
||||
getLocationPlaceholder,
|
||||
clearable,
|
||||
popOverContainer,
|
||||
vendor,
|
||||
coordinatesType,
|
||||
ak,
|
||||
mobileUI
|
||||
mobileUI,
|
||||
autoSelectCurrentLoc,
|
||||
onlySelectCurrentLoc
|
||||
} = this.props;
|
||||
const __ = this.props.translate;
|
||||
const {isFocused, isOpened} = this.state;
|
||||
@ -173,6 +180,8 @@ export class LocationPicker extends React.Component<
|
||||
ak={ak}
|
||||
value={value}
|
||||
coordinatesType={coordinatesType}
|
||||
autoSelectCurrentLoc={autoSelectCurrentLoc}
|
||||
onlySelectCurrentLoc={onlySelectCurrentLoc}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
);
|
||||
@ -213,7 +222,7 @@ export class LocationPicker extends React.Component<
|
||||
<span className={cx('LocationPicker-value')}>{value.address}</span>
|
||||
) : (
|
||||
<span className={cx('LocationPicker-placeholder')}>
|
||||
{__(placeholder)}
|
||||
{__(onlySelectCurrentLoc ? getLocationPlaceholder : placeholder)}
|
||||
</span>
|
||||
)}
|
||||
|
||||
@ -242,6 +251,8 @@ export class LocationPicker extends React.Component<
|
||||
ak={ak}
|
||||
value={value}
|
||||
coordinatesType={coordinatesType}
|
||||
autoSelectCurrentLoc={autoSelectCurrentLoc}
|
||||
onlySelectCurrentLoc={onlySelectCurrentLoc}
|
||||
onChange={this.handleTempChange}
|
||||
/>
|
||||
) : (
|
||||
@ -268,6 +279,8 @@ export class LocationPicker extends React.Component<
|
||||
ak={ak}
|
||||
value={value}
|
||||
coordinatesType={coordinatesType}
|
||||
autoSelectCurrentLoc={autoSelectCurrentLoc}
|
||||
onlySelectCurrentLoc={onlySelectCurrentLoc}
|
||||
onChange={this.handleChange}
|
||||
/>
|
||||
) : (
|
||||
|
@ -1271,7 +1271,7 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
||||
>
|
||||
<PopOver
|
||||
overlay
|
||||
className={cx('Select-popover')}
|
||||
className={cx('Select-popover', popoverClassName)}
|
||||
style={{
|
||||
width:
|
||||
(overlay &&
|
||||
|
@ -35,6 +35,8 @@ export interface SpinnerProps extends ThemeProps, SpinnerExtraProps {
|
||||
tipPlacement?: 'top' | 'right' | 'bottom' | 'left'; // spinner文案位置
|
||||
delay?: number; // 延迟显示
|
||||
overlay?: boolean; // 是否显示遮罩层,有children属性才生效
|
||||
/** 是否处于禁用状态 */
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export interface SpinnerExtraProps {
|
||||
@ -114,7 +116,8 @@ export class Spinner extends React.Component<
|
||||
tipPlacement: 'bottom' as 'bottom',
|
||||
delay: 0,
|
||||
overlay: false,
|
||||
loadingConfig: {}
|
||||
loadingConfig: {},
|
||||
disabled: false
|
||||
};
|
||||
|
||||
state = {
|
||||
@ -190,7 +193,8 @@ export class Spinner extends React.Component<
|
||||
icon: iconConfig,
|
||||
tip,
|
||||
tipPlacement = '',
|
||||
loadingConfig
|
||||
loadingConfig,
|
||||
disabled
|
||||
} = this.props;
|
||||
// 定义了挂载位置时只能使用默认icon
|
||||
const icon = loadingConfig?.root ? undefined : iconConfig;
|
||||
@ -241,9 +245,10 @@ export class Spinner extends React.Component<
|
||||
`Spinner-icon`,
|
||||
{
|
||||
[`Spinner-icon--${size}`]: ['lg', 'sm'].includes(size),
|
||||
[`Spinner-icon--default`]: !icon,
|
||||
[`Spinner-icon--simple`]: !isCustomIcon && icon,
|
||||
[`Spinner-icon--custom`]: isCustomIcon
|
||||
'Spinner-icon--default': !icon,
|
||||
'Spinner-icon--simple': !isCustomIcon && icon,
|
||||
'Spinner-icon--custom': isCustomIcon,
|
||||
'Spinner-icon--disabled': disabled
|
||||
},
|
||||
spinnerClassName
|
||||
)}
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
import React from 'react';
|
||||
import {ClassNamesFn, themeable} from 'amis-core';
|
||||
import {classPrefix, classnames} from '../themes/default';
|
||||
import {Spinner} from './Spinner';
|
||||
|
||||
const sizeMap = {
|
||||
sm: 'Switch--sm',
|
||||
@ -39,6 +39,11 @@ interface SwitchProps {
|
||||
onText?: React.ReactNode;
|
||||
offText?: React.ReactNode;
|
||||
checked?: boolean;
|
||||
loading?: boolean;
|
||||
loadingConfig?: {
|
||||
root?: string;
|
||||
show?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export class Switch extends React.PureComponent<SwitchProps, any> {
|
||||
@ -80,6 +85,8 @@ export class Switch extends React.PureComponent<SwitchProps, any> {
|
||||
readOnly,
|
||||
checked,
|
||||
classnames: cx,
|
||||
loading,
|
||||
loadingConfig,
|
||||
...rest
|
||||
} = this.props;
|
||||
|
||||
@ -94,27 +101,42 @@ export class Switch extends React.PureComponent<SwitchProps, any> {
|
||||
: typeof value === 'undefined'
|
||||
? false
|
||||
: value == trueValue;
|
||||
const isDisabled = disabled || loading;
|
||||
|
||||
return (
|
||||
<label
|
||||
className={cx(
|
||||
`Switch`,
|
||||
isChecked ? 'is-checked' : '',
|
||||
disabled ? 'is-disabled' : '',
|
||||
className
|
||||
)}
|
||||
className={cx(`Switch`, className, {
|
||||
'is-checked': isChecked,
|
||||
'is-disabled': isDisabled
|
||||
})}
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={isChecked}
|
||||
onChange={this.hanldeCheck}
|
||||
disabled={disabled}
|
||||
disabled={isDisabled}
|
||||
readOnly={readOnly}
|
||||
{...rest}
|
||||
/>
|
||||
|
||||
<span className="text">{isChecked ? onText : offText}</span>
|
||||
<span className="slider"></span>
|
||||
<span className="slider">
|
||||
{loading ? (
|
||||
<Spinner
|
||||
classnames={cx}
|
||||
classPrefix={classPrefix}
|
||||
className={cx('Switch-spinner', {
|
||||
'Switch-spinner--sm': size === 'sm',
|
||||
'Switch-spinner--checked': isChecked
|
||||
})}
|
||||
spinnerClassName={cx('Switch-spinner-icon')}
|
||||
disabled={!isChecked}
|
||||
size="sm"
|
||||
icon="loading-outline"
|
||||
loadingConfig={loadingConfig}
|
||||
/>
|
||||
) : null}
|
||||
</span>
|
||||
</label>
|
||||
);
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ const FormulaInput: React.FC<FormulaInputProps> = props => {
|
||||
} = props;
|
||||
const schemaType = inputSettings.type;
|
||||
/** 自上层共享的属性 */
|
||||
const sharedProps = pick(props, ['disabeld', 'clearable']);
|
||||
const sharedProps = pick(props, ['disabled', 'clearable']);
|
||||
const pipInValue = useCallback(
|
||||
(value?: any) => {
|
||||
return value;
|
||||
|
@ -188,6 +188,8 @@ register('de-DE', {
|
||||
'loading': 'Wird geladen...',
|
||||
'loadingFailed': 'Das Laden ist fehlgeschlagen',
|
||||
'LocationPicker.placeholder': 'Wählen Sie einen Ort',
|
||||
'LocationPicker.getLocation':
|
||||
'Klicken Sie hier, um Standortinformationen zu erhalten',
|
||||
'Month.placeholder': 'Wählen Sie einen Monat',
|
||||
'Nav.sourceError': 'Fehler beim Abrufen des Links',
|
||||
'networkError':
|
||||
|
@ -180,6 +180,7 @@ register('en-US', {
|
||||
'loading': 'Loading',
|
||||
'loadingFailed': 'Loading failed',
|
||||
'LocationPicker.placeholder': 'Pick location',
|
||||
'LocationPicker.getLocation': 'Click to obtain location information',
|
||||
'Month.placeholder': 'Select a month',
|
||||
'Nav.sourceError': 'Fetch link error',
|
||||
'networkError': 'Network error or missing CORS configuration',
|
||||
|
@ -185,6 +185,7 @@ register('zh-CN', {
|
||||
'loading': '加载中',
|
||||
'loadingFailed': '加载失败',
|
||||
'LocationPicker.placeholder': '请选择位置',
|
||||
'LocationPicker.getLocation': '点击获取位置信息',
|
||||
'Month.placeholder': '请选择月份',
|
||||
'Nav.sourceError': '获取链接错误',
|
||||
'networkError': '网络错误,可能是未配置跨域 CORS',
|
||||
|
@ -28,7 +28,7 @@ exports[`doAction:crud reload 1`] = `
|
||||
>
|
||||
<div
|
||||
class="cxd-Table cxd-Crud-body"
|
||||
style="--Table-column-3-width: 0px; --Table-column-4-width: 0px; --Table-column-5-width: 0px; --Table-column-6-width: 0px; --Table-column-7-width: 0px; --Table-column-8-width: 0px; --Table-column-9-width: 0px; position: relative;"
|
||||
style="--Table-thead-height: 0px; --Table-column-3-width: 0px; --Table-column-4-width: 0px; --Table-column-5-width: 0px; --Table-column-6-width: 0px; --Table-column-7-width: 0px; --Table-column-8-width: 0px; --Table-column-9-width: 0px; position: relative;"
|
||||
>
|
||||
<div
|
||||
class="cxd-Table-fixedTop"
|
||||
@ -335,7 +335,7 @@ exports[`doAction:crud reload with data1 1`] = `
|
||||
>
|
||||
<div
|
||||
class="cxd-Table cxd-Crud-body"
|
||||
style="--Table-column-3-width: 0px; --Table-column-4-width: 0px; --Table-column-5-width: 0px; --Table-column-6-width: 0px; --Table-column-7-width: 0px; --Table-column-8-width: 0px; --Table-column-9-width: 0px; position: relative;"
|
||||
style="--Table-thead-height: 0px; --Table-column-3-width: 0px; --Table-column-4-width: 0px; --Table-column-5-width: 0px; --Table-column-6-width: 0px; --Table-column-7-width: 0px; --Table-column-8-width: 0px; --Table-column-9-width: 0px; position: relative;"
|
||||
>
|
||||
<div
|
||||
class="cxd-Table-fixedTop"
|
||||
@ -642,7 +642,7 @@ exports[`doAction:crud reload with data2 1`] = `
|
||||
>
|
||||
<div
|
||||
class="cxd-Table cxd-Crud-body"
|
||||
style="--Table-column-3-width: 0px; --Table-column-4-width: 0px; --Table-column-5-width: 0px; --Table-column-6-width: 0px; --Table-column-7-width: 0px; --Table-column-8-width: 0px; --Table-column-9-width: 0px; position: relative;"
|
||||
style="--Table-thead-height: 0px; --Table-column-3-width: 0px; --Table-column-4-width: 0px; --Table-column-5-width: 0px; --Table-column-6-width: 0px; --Table-column-7-width: 0px; --Table-column-8-width: 0px; --Table-column-9-width: 0px; position: relative;"
|
||||
>
|
||||
<div
|
||||
class="cxd-Table-fixedTop"
|
||||
|
@ -53,7 +53,7 @@ exports[`Renderer:input table 1`] = `
|
||||
>
|
||||
<div
|
||||
class="cxd-Table"
|
||||
style="--Table-column-3-width: 0px; --Table-column-4-width: 0px; position: relative;"
|
||||
style="--Table-thead-height: 0px; --Table-column-3-width: 0px; --Table-column-4-width: 0px; position: relative;"
|
||||
>
|
||||
<div
|
||||
class="cxd-Table-contentWrap"
|
||||
@ -378,7 +378,7 @@ exports[`Renderer:input table add 1`] = `
|
||||
>
|
||||
<div
|
||||
class="cxd-Table"
|
||||
style="--Table-column-3-width: 0px; --Table-column-4-width: 0px; --Table-column-5-width: 0px; position: relative;"
|
||||
style="--Table-thead-height: 0px; --Table-column-3-width: 0px; --Table-column-4-width: 0px; --Table-column-5-width: 0px; position: relative;"
|
||||
>
|
||||
<div
|
||||
class="cxd-Table-contentWrap"
|
||||
@ -690,7 +690,7 @@ exports[`Renderer:input-table cell selects delete 1`] = `
|
||||
>
|
||||
<div
|
||||
class="cxd-Table"
|
||||
style="--Table-column-3-width: 0px; --Table-column-4-width: 0px; position: relative;"
|
||||
style="--Table-thead-height: 0px; --Table-column-3-width: 0px; --Table-column-4-width: 0px; position: relative;"
|
||||
>
|
||||
<div
|
||||
class="cxd-Table-contentWrap"
|
||||
@ -1029,7 +1029,7 @@ exports[`Renderer:input-table init display 1`] = `
|
||||
>
|
||||
<div
|
||||
class="cxd-Table"
|
||||
style="--Table-column-3-width: 0px; --Table-column-4-width: 0px; --Table-column-5-width: 0px; --Table-column-6-width: 0px; position: relative;"
|
||||
style="--Table-thead-height: 0px; --Table-column-3-width: 0px; --Table-column-4-width: 0px; --Table-column-5-width: 0px; --Table-column-6-width: 0px; position: relative;"
|
||||
>
|
||||
<div
|
||||
class="cxd-Table-contentWrap"
|
||||
@ -1716,7 +1716,7 @@ exports[`Renderer:input-table with combo column 1`] = `
|
||||
>
|
||||
<div
|
||||
class="cxd-Table"
|
||||
style="--Table-column-3-width: 0px; position: relative;"
|
||||
style="--Table-thead-height: 0px; --Table-column-3-width: 0px; position: relative;"
|
||||
>
|
||||
<div
|
||||
class="cxd-Table-contentWrap"
|
||||
|
@ -659,6 +659,17 @@ test('Renderer:combo with canAccessSuperData & strictMode & syncFields', async (
|
||||
expect(comboInputs[0]!.value).toBe('');
|
||||
expect(comboInputs[1]!.value).toBe('123');
|
||||
expect(comboInputs[2]!.value).toBe('123456');
|
||||
|
||||
fireEvent.click(submitBtn);
|
||||
await wait(300);
|
||||
expect(onSubmit).toHaveBeenCalled();
|
||||
|
||||
expect(onSubmit.mock.calls[0][0]).toMatchObject({
|
||||
super_text: '123456',
|
||||
combo1: [{}],
|
||||
combo2: [{super_text: '123'}],
|
||||
combo3: [{super_text: '123456'}]
|
||||
});
|
||||
});
|
||||
|
||||
// 9. tabsMode
|
||||
|
@ -194,6 +194,7 @@ test('Renderer:inputArray with minLength & maxLength', async () => {
|
||||
expect(container.querySelector('.cxd-Combo-addBtn')).toBeInTheDocument();
|
||||
// 最大值
|
||||
fireEvent.click(container.querySelector('.cxd-Combo-addBtn')!);
|
||||
await wait(300);
|
||||
await waitFor(() => {
|
||||
expect(container.querySelector('a.cxd-Combo-delBtn')).toBeInTheDocument();
|
||||
expect(
|
||||
|
@ -540,4 +540,44 @@ test('Renderer:inputDate defaultValue with formula', async () => {
|
||||
|
||||
expect(input).toBeInTheDocument();
|
||||
expect(input.value).toBe('2021-12-06');
|
||||
|
||||
});
|
||||
|
||||
test('Renderer:inputDate setValue actions with special words', async () => {
|
||||
const {container, submitBtn, onSubmit, getByText} = await setup([
|
||||
{
|
||||
type: 'input-date',
|
||||
name: 'date',
|
||||
id: 'date',
|
||||
label: '日期',
|
||||
format: 'YYYY-MM-DD'
|
||||
},
|
||||
|
||||
{
|
||||
type: 'button',
|
||||
label: '设置值',
|
||||
onEvent: {
|
||||
click: {
|
||||
actions: [
|
||||
{
|
||||
actionType: 'setValue',
|
||||
componentId: 'date',
|
||||
args: {
|
||||
value: 'today'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
// 打开弹框
|
||||
fireEvent.click(getByText('设置值'));
|
||||
await wait(200);
|
||||
const today = moment();
|
||||
const inputDate = container.querySelector('.cxd-DatePicker-input');
|
||||
|
||||
expect(inputDate).toBeInTheDocument();
|
||||
expect((inputDate as any)?.value).toEqual(today.format('YYYY-MM-DD'));
|
||||
});
|
||||
|
@ -0,0 +1,92 @@
|
||||
/**
|
||||
* 组件名称:InputDateRange 日期
|
||||
*
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PageRenderer from '../../../../amis-core/src/renderers/Form';
|
||||
import * as renderer from 'react-test-renderer';
|
||||
import {
|
||||
render,
|
||||
fireEvent,
|
||||
cleanup,
|
||||
getByText,
|
||||
waitFor,
|
||||
screen
|
||||
} from '@testing-library/react';
|
||||
import '../../../src';
|
||||
import {render as amisRender} from '../../../src';
|
||||
import {makeEnv, wait} from '../../helper';
|
||||
import moment from 'moment';
|
||||
|
||||
const setup = async (items: any[] = []) => {
|
||||
const onSubmit = jest.fn();
|
||||
const utils = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'page',
|
||||
body: {
|
||||
type: 'form',
|
||||
submitText: 'Submit',
|
||||
api: '/api/mock/saveForm?waitSeconds=1',
|
||||
mode: 'horizontal',
|
||||
body: items
|
||||
}
|
||||
},
|
||||
{onSubmit},
|
||||
makeEnv()
|
||||
)
|
||||
);
|
||||
|
||||
const submitBtn = utils.container.querySelector(
|
||||
'button[type="submit"]'
|
||||
) as HTMLElement;
|
||||
|
||||
return {
|
||||
onSubmit,
|
||||
submitBtn,
|
||||
...utils
|
||||
};
|
||||
};
|
||||
|
||||
test('1.Renderer:inputDateRange setValue actions with special words', async () => {
|
||||
const {container, submitBtn, onSubmit, getByText} = await setup([
|
||||
{
|
||||
type: 'input-date-range',
|
||||
name: 'date',
|
||||
id: 'date',
|
||||
label: '日期',
|
||||
format: 'YYYY-MM-DD'
|
||||
},
|
||||
|
||||
{
|
||||
type: 'button',
|
||||
label: '设置值',
|
||||
onEvent: {
|
||||
click: {
|
||||
actions: [
|
||||
{
|
||||
actionType: 'setValue',
|
||||
componentId: 'date',
|
||||
args: {
|
||||
value: 'today,+2days'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
// 打开弹框
|
||||
fireEvent.click(getByText('设置值'));
|
||||
await wait(200);
|
||||
const today = moment();
|
||||
const inputDates = container.querySelectorAll('.cxd-DateRangePicker-input');
|
||||
expect(inputDates.length).toBe(2);
|
||||
|
||||
expect((inputDates[0] as any)?.value).toEqual(today.format('YYYY-MM-DD'));
|
||||
expect((inputDates[1] as any)?.value).toEqual(
|
||||
moment(today).add(2, 'days').format('YYYY-MM-DD')
|
||||
);
|
||||
});
|
@ -71,3 +71,42 @@ describe('Renderer:Switch', () => {
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* 默认状态为开启时
|
||||
* 默认状态为关闭时
|
||||
* 默认状态为禁用时
|
||||
*/
|
||||
test('Renderer:Switch with loading status', async () => {
|
||||
const {container} = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'form',
|
||||
body: [
|
||||
{
|
||||
"type": "switch",
|
||||
"name": "switch1",
|
||||
"label": "",
|
||||
"loading": true,
|
||||
"value": true
|
||||
},
|
||||
{
|
||||
"type": "switch",
|
||||
"name": "switch2",
|
||||
"label": "",
|
||||
"disabled": true,
|
||||
"loading": true,
|
||||
"value": false
|
||||
}
|
||||
],
|
||||
actions: []
|
||||
},
|
||||
{},
|
||||
makeEnv()
|
||||
)
|
||||
);
|
||||
|
||||
const loadingDom = container.querySelectorAll('.cxd-Switch-spinner');
|
||||
|
||||
expect(loadingDom?.length).toEqual(2);
|
||||
});
|
||||
|
@ -958,19 +958,7 @@ describe('Renderer:table selectable & itemCheckableOn', () => {
|
||||
]
|
||||
};
|
||||
|
||||
test('radio style', async () => {
|
||||
const {container} = render(amisRender(schema, {}, makeEnv({})));
|
||||
await waitFor(() => {
|
||||
expect(container.querySelector('[type=radio]')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
expect(
|
||||
container.querySelector('[data-id="1"] [type=radio][disabled=""]')!
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('checkbox style', async () => {
|
||||
schema.multiple = true;
|
||||
const {container} = render(amisRender(schema, {}, makeEnv({})));
|
||||
await waitFor(() => {
|
||||
expect(container.querySelector('[type=checkbox]')).toBeInTheDocument();
|
||||
@ -980,6 +968,18 @@ describe('Renderer:table selectable & itemCheckableOn', () => {
|
||||
container.querySelector('[data-id="1"] [type=checkbox][disabled=""]')!
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('radio style', async () => {
|
||||
schema.multiple = false;
|
||||
const {container} = render(amisRender(schema, {}, makeEnv({})));
|
||||
await waitFor(() => {
|
||||
expect(container.querySelector('[type=radio]')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
expect(
|
||||
container.querySelector('[data-id="1"] [type=radio][disabled=""]')!
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('dbClick', () => {
|
||||
|
@ -20,7 +20,7 @@ exports[`1. Renderer:crud basic interval headerToolbar footerToolbar 1`] = `
|
||||
>
|
||||
<div
|
||||
class="cxd-Table cxd-Crud-body"
|
||||
style="--Table-column-3-width: 0px; --Table-column-4-width: 0px; --Table-column-5-width: 0px; position: relative;"
|
||||
style="--Table-thead-height: 0px; --Table-column-3-width: 0px; --Table-column-4-width: 0px; --Table-column-5-width: 0px; position: relative;"
|
||||
>
|
||||
<div
|
||||
class="cxd-Table-fixedTop"
|
||||
@ -2157,7 +2157,7 @@ exports[`6. Renderer:crud source & alwaysShowPagination 1`] = `
|
||||
>
|
||||
<div
|
||||
class="cxd-Table cxd-Crud-body"
|
||||
style="--Table-column-3-width: 0px; --Table-column-4-width: 0px; --Table-column-5-width: 0px; position: relative;"
|
||||
style="--Table-thead-height: 0px; --Table-column-3-width: 0px; --Table-column-4-width: 0px; --Table-column-5-width: 0px; position: relative;"
|
||||
>
|
||||
<div
|
||||
class="cxd-Table-fixedTop"
|
||||
@ -2799,7 +2799,7 @@ exports[`13. enderer: crud keepItemSelectionOnPageChange & maxKeepItemSelectionL
|
||||
</div>
|
||||
<div
|
||||
class="cxd-Table cxd-Crud-body"
|
||||
style="--Table-column-3-width: 0px; --Table-column-4-width: 0px; position: relative; --Table-column-1-width: 0px;"
|
||||
style="--Table-thead-height: 0px; --Table-column-3-width: 0px; --Table-column-4-width: 0px; position: relative; --Table-column-1-width: 0px;"
|
||||
>
|
||||
<div
|
||||
class="cxd-Table-fixedTop"
|
||||
|
@ -83,7 +83,7 @@ exports[`Renderer:Pagination 1`] = `
|
||||
</div>
|
||||
<div
|
||||
class="cxd-Table"
|
||||
style="--Table-column-3-width: 0px; --Table-column-4-width: 0px; position: relative;"
|
||||
style="--Table-thead-height: 0px; --Table-column-3-width: 0px; --Table-column-4-width: 0px; position: relative;"
|
||||
>
|
||||
<div
|
||||
class="cxd-Table-fixedTop"
|
||||
|
@ -4,7 +4,7 @@ exports[`Renderer:table 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="cxd-Table"
|
||||
style="--Table-column-3-width: 0px; --Table-column-4-width: 0px; position: relative;"
|
||||
style="--Table-thead-height: 0px; --Table-column-3-width: 0px; --Table-column-4-width: 0px; position: relative;"
|
||||
>
|
||||
<div
|
||||
class="cxd-Table-fixedTop"
|
||||
@ -370,7 +370,7 @@ exports[`Renderer:table align 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="cxd-Table"
|
||||
style="--Table-column-3-width: 0px; --Table-column-4-width: 0px; position: relative;"
|
||||
style="--Table-thead-height: 0px; --Table-column-3-width: 0px; --Table-column-4-width: 0px; position: relative;"
|
||||
>
|
||||
<div
|
||||
class="cxd-Table-fixedTop"
|
||||
@ -775,7 +775,7 @@ exports[`Renderer:table children 1`] = `
|
||||
>
|
||||
<div
|
||||
class="cxd-Table m-b-none"
|
||||
style="--Table-column-3-width: 0px; --Table-column-4-width: 0px; --Table-column-5-width: 0px; --Table-column-6-width: 0px; --Table-column-7-width: 0px; --Table-column-8-width: 0px; position: relative;"
|
||||
style="--Table-thead-height: 0px; --Table-column-3-width: 0px; --Table-column-4-width: 0px; --Table-column-5-width: 0px; --Table-column-6-width: 0px; --Table-column-7-width: 0px; --Table-column-8-width: 0px; position: relative;"
|
||||
>
|
||||
<div
|
||||
class="cxd-Table-fixedTop"
|
||||
@ -1355,7 +1355,7 @@ exports[`Renderer:table classNameExpr 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="cxd-Table"
|
||||
style="--Table-column-3-width: 0px; --Table-column-4-width: 0px; position: relative;"
|
||||
style="--Table-thead-height: 0px; --Table-column-3-width: 0px; --Table-column-4-width: 0px; position: relative;"
|
||||
>
|
||||
<div
|
||||
class="cxd-Table-fixedTop"
|
||||
@ -1721,7 +1721,7 @@ exports[`Renderer:table column head style className 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="cxd-Table className"
|
||||
style="--Table-column-3-width: 0px; --Table-column-4-width: 0px; position: relative;"
|
||||
style="--Table-thead-height: 0px; --Table-column-3-width: 0px; --Table-column-4-width: 0px; position: relative;"
|
||||
>
|
||||
<div
|
||||
class="cxd-Table-fixedTop"
|
||||
@ -2114,7 +2114,7 @@ exports[`Renderer:table combine Renderer:table combineNum only 1`] = `
|
||||
>
|
||||
<div
|
||||
class="cxd-Table"
|
||||
style="--Table-column-3-width: 0px; --Table-column-4-width: 0px; --Table-column-5-width: 0px; --Table-column-6-width: 0px; --Table-column-7-width: 0px; position: relative;"
|
||||
style="--Table-thead-height: 0px; --Table-column-3-width: 0px; --Table-column-4-width: 0px; --Table-column-5-width: 0px; --Table-column-6-width: 0px; --Table-column-7-width: 0px; position: relative;"
|
||||
>
|
||||
<div
|
||||
class="cxd-Table-fixedTop"
|
||||
@ -2689,7 +2689,7 @@ exports[`Renderer:table combine Renderer:table combineNum with fromIndex 1`] = `
|
||||
>
|
||||
<div
|
||||
class="cxd-Table"
|
||||
style="--Table-column-3-width: 0px; --Table-column-4-width: 0px; --Table-column-5-width: 0px; --Table-column-6-width: 0px; --Table-column-7-width: 0px; position: relative;"
|
||||
style="--Table-thead-height: 0px; --Table-column-3-width: 0px; --Table-column-4-width: 0px; --Table-column-5-width: 0px; --Table-column-6-width: 0px; --Table-column-7-width: 0px; position: relative;"
|
||||
>
|
||||
<div
|
||||
class="cxd-Table-fixedTop"
|
||||
@ -3334,7 +3334,7 @@ exports[`Renderer:table groupName-default 1`] = `
|
||||
>
|
||||
<div
|
||||
class="cxd-Table m-b-none"
|
||||
style="--Table-column-3-width: 0px; --Table-column-4-width: 0px; --Table-column-5-width: 0px; --Table-column-6-width: 0px; --Table-column-8-width: 0px; position: relative;"
|
||||
style="--Table-thead-height: 0px; --Table-column-3-width: 0px; --Table-column-4-width: 0px; --Table-column-5-width: 0px; --Table-column-6-width: 0px; --Table-column-8-width: 0px; position: relative;"
|
||||
>
|
||||
<div
|
||||
class="cxd-Table-fixedTop"
|
||||
@ -4113,7 +4113,7 @@ exports[`Renderer:table groupName-middleNoGroupName 1`] = `
|
||||
>
|
||||
<div
|
||||
class="cxd-Table m-b-none"
|
||||
style="--Table-column-3-width: 0px; --Table-column-4-width: 0px; --Table-column-5-width: 0px; --Table-column-6-width: 0px; --Table-column-8-width: 0px; position: relative;"
|
||||
style="--Table-thead-height: 0px; --Table-column-3-width: 0px; --Table-column-4-width: 0px; --Table-column-5-width: 0px; --Table-column-6-width: 0px; --Table-column-8-width: 0px; position: relative;"
|
||||
>
|
||||
<div
|
||||
class="cxd-Table-fixedTop"
|
||||
@ -4896,7 +4896,7 @@ exports[`Renderer:table groupName-startNoGroupName 1`] = `
|
||||
>
|
||||
<div
|
||||
class="cxd-Table m-b-none"
|
||||
style="--Table-column-3-width: 0px; --Table-column-4-width: 0px; --Table-column-5-width: 0px; --Table-column-6-width: 0px; --Table-column-8-width: 0px; position: relative;"
|
||||
style="--Table-thead-height: 0px; --Table-column-3-width: 0px; --Table-column-4-width: 0px; --Table-column-5-width: 0px; --Table-column-6-width: 0px; --Table-column-8-width: 0px; position: relative;"
|
||||
>
|
||||
<div
|
||||
class="cxd-Table-fixedTop"
|
||||
@ -5667,7 +5667,7 @@ exports[`Renderer:table groupName-withTpl 1`] = `
|
||||
>
|
||||
<div
|
||||
class="cxd-Table m-b-none"
|
||||
style="--Table-column-3-width: 0px; --Table-column-4-width: 0px; --Table-column-5-width: 0px; --Table-column-6-width: 0px; --Table-column-8-width: 0px; position: relative;"
|
||||
style="--Table-thead-height: 0px; --Table-column-3-width: 0px; --Table-column-4-width: 0px; --Table-column-5-width: 0px; --Table-column-6-width: 0px; --Table-column-8-width: 0px; position: relative;"
|
||||
>
|
||||
<div
|
||||
class="cxd-Table-fixedTop"
|
||||
@ -6430,7 +6430,7 @@ exports[`Renderer:table isHead fixed 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="cxd-Table"
|
||||
style="--Table-column-3-width: 0px; --Table-column-4-width: 0px; position: relative;"
|
||||
style="--Table-thead-height: 0px; --Table-column-3-width: 0px; --Table-column-4-width: 0px; position: relative;"
|
||||
>
|
||||
<div
|
||||
class="cxd-Table-fixedTop"
|
||||
@ -6807,7 +6807,7 @@ exports[`Renderer:table list 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="cxd-Table"
|
||||
style="--Table-column-3-width: 0px; --Table-column-4-width: 0px; --Table-column-5-width: 0px; --Table-column-6-width: 0px; --Table-column-7-width: 0px; --Table-column-8-width: 0px; --Table-column-9-width: 0px; --Table-column-10-width: 0px; --Table-column-11-width: 0px; position: relative;"
|
||||
style="--Table-thead-height: 0px; --Table-column-3-width: 0px; --Table-column-4-width: 0px; --Table-column-5-width: 0px; --Table-column-6-width: 0px; --Table-column-7-width: 0px; --Table-column-8-width: 0px; --Table-column-9-width: 0px; --Table-column-10-width: 0px; --Table-column-11-width: 0px; position: relative;"
|
||||
>
|
||||
<div
|
||||
class="cxd-Table-toolbar cxd-Table-headToolbar"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "amis",
|
||||
"version": "3.5.1",
|
||||
"version": "3.5.3",
|
||||
"description": "一种MIS页面生成工具",
|
||||
"main": "lib/index.js",
|
||||
"module": "esm/index.js",
|
||||
@ -37,8 +37,8 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"amis-core": "^3.5.1",
|
||||
"amis-ui": "^3.5.1",
|
||||
"amis-core": "^3.5.3",
|
||||
"amis-ui": "^3.5.3",
|
||||
"attr-accept": "2.2.2",
|
||||
"blueimp-canvastoblob": "2.1.0",
|
||||
"classnames": "2.3.2",
|
||||
@ -67,7 +67,6 @@
|
||||
"qrcode.react": "^3.1.0",
|
||||
"react-cropper": "^2.1.8",
|
||||
"react-dropzone": "^11.4.2",
|
||||
"react-error-boundary": "^4.0.11",
|
||||
"react-intersection-observer": "9.5.2",
|
||||
"react-json-view": "1.21.3",
|
||||
"react-transition-group": "4.4.2",
|
||||
|
@ -6,7 +6,8 @@ import {
|
||||
isPureVariable,
|
||||
resolveVariableAndFilter,
|
||||
setVariable,
|
||||
setThemeClassName
|
||||
setThemeClassName,
|
||||
ValidateError
|
||||
} from 'amis-core';
|
||||
import {Renderer, RendererProps} from 'amis-core';
|
||||
import {SchemaNode, Schema, ActionObject} from 'amis-core';
|
||||
@ -805,6 +806,7 @@ export default class Dialog extends React.Component<DialogProps> {
|
||||
})
|
||||
export class DialogRenderer extends Dialog {
|
||||
static contextType = ScopedContext;
|
||||
clearErrorTimer: ReturnType<typeof setTimeout>;
|
||||
|
||||
constructor(props: DialogProps, context: IScopedContext) {
|
||||
super(props);
|
||||
@ -817,6 +819,7 @@ export class DialogRenderer extends Dialog {
|
||||
const scoped = this.context as IScopedContext;
|
||||
scoped.unRegisterComponent(this);
|
||||
super.componentWillUnmount();
|
||||
clearTimeout(this.clearErrorTimer);
|
||||
}
|
||||
|
||||
tryChildrenToHandle(
|
||||
@ -897,6 +900,16 @@ export class DialogRenderer extends Dialog {
|
||||
}
|
||||
store.updateMessage(reason.message, true);
|
||||
store.markBusying(false);
|
||||
|
||||
if (reason.constructor?.name === ValidateError.name) {
|
||||
clearTimeout(this.clearErrorTimer);
|
||||
this.clearErrorTimer = setTimeout(() => {
|
||||
if (this.isDead) {
|
||||
return;
|
||||
}
|
||||
store.updateMessage('');
|
||||
}, 3000);
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
|
@ -5,7 +5,8 @@ import {
|
||||
filterTarget,
|
||||
isPureVariable,
|
||||
resolveVariableAndFilter,
|
||||
setThemeClassName
|
||||
setThemeClassName,
|
||||
ValidateError
|
||||
} from 'amis-core';
|
||||
import {Renderer, RendererProps} from 'amis-core';
|
||||
import {SchemaNode, Schema, ActionObject} from 'amis-core';
|
||||
@ -214,6 +215,7 @@ export default class Drawer extends React.Component<DrawerProps> {
|
||||
reaction: any;
|
||||
$$id: string = guid();
|
||||
drawer: any;
|
||||
clearErrorTimer: ReturnType<typeof setTimeout> | undefined;
|
||||
constructor(props: DrawerProps) {
|
||||
super(props);
|
||||
|
||||
@ -251,6 +253,7 @@ export default class Drawer extends React.Component<DrawerProps> {
|
||||
|
||||
componentWillUnmount() {
|
||||
this.reaction && this.reaction();
|
||||
clearTimeout(this.clearErrorTimer);
|
||||
}
|
||||
|
||||
buildActions(): Array<ActionSchema> {
|
||||
@ -850,6 +853,13 @@ export class DrawerRenderer extends Drawer {
|
||||
.catch(reason => {
|
||||
store.updateMessage(reason.message, true);
|
||||
store.markBusying(false);
|
||||
|
||||
if (reason.constructor?.name === ValidateError.name) {
|
||||
clearTimeout(this.clearErrorTimer);
|
||||
this.clearErrorTimer = setTimeout(() => {
|
||||
store.updateMessage('');
|
||||
}, 3000);
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
|
@ -541,8 +541,10 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
}
|
||||
|
||||
getValueAsArray(props = this.props) {
|
||||
const {flat, joinValues, delimiter, type} = props;
|
||||
let value = props.value;
|
||||
const {flat, joinValues, delimiter, type, formItem} = props;
|
||||
// 因为 combo 多个子表单可能同时发生变化。
|
||||
// onChagne 触发多次,上次变更还没应用到 props.value 上来,这次触发变更就会包含历史数据,把上次触发的数据给重置成旧的了。
|
||||
let value = formItem?.tmpValue || props.value;
|
||||
|
||||
if (joinValues && flat && typeof value === 'string') {
|
||||
value = value.split(delimiter || ',');
|
||||
|
@ -565,6 +565,21 @@ export default class DateControl extends React.PureComponent<
|
||||
}
|
||||
}
|
||||
|
||||
setData(value: any) {
|
||||
const {data, valueFormat, format, utc, onChange} = this.props;
|
||||
|
||||
if (
|
||||
typeof value === 'string' ||
|
||||
typeof value === 'number' ||
|
||||
value instanceof Date
|
||||
) {
|
||||
const date = filterDate(value as any, data, valueFormat || format);
|
||||
value = (utc ? moment.utc(date) : date).format(valueFormat || format);
|
||||
}
|
||||
|
||||
onChange(value);
|
||||
}
|
||||
|
||||
// 值的变化
|
||||
@autobind
|
||||
async handleChange(nextValue: any) {
|
||||
|
@ -246,6 +246,27 @@ export default class DateRangeControl extends React.Component<DateRangeProps> {
|
||||
}
|
||||
}
|
||||
|
||||
setData(value: any) {
|
||||
const {data, delimiter, valueFormat, format, joinValues, utc, onChange} =
|
||||
this.props;
|
||||
|
||||
if (typeof value === 'string') {
|
||||
let arr = typeof value === 'string' ? value.split(delimiter) : value;
|
||||
value = DateRangePicker.formatValue(
|
||||
{
|
||||
startDate: filterDate(arr[0], data, valueFormat || format),
|
||||
endDate: filterDate(arr[1], data, valueFormat || format)
|
||||
},
|
||||
valueFormat || format,
|
||||
joinValues,
|
||||
delimiter,
|
||||
utc
|
||||
);
|
||||
}
|
||||
|
||||
onChange(value);
|
||||
}
|
||||
|
||||
// 值的变化
|
||||
@autobind
|
||||
async handleChange(nextValue: any) {
|
||||
|
@ -1775,10 +1775,6 @@ export class TableControlRenderer extends FormTable {
|
||||
const ctx = this.props.store?.data || {}; // 获取当前上下文数据
|
||||
|
||||
if (actionType === 'addItem') {
|
||||
if (addable === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
const items = this.state.items.concat();
|
||||
|
||||
if (addApi || args) {
|
||||
|
@ -29,6 +29,23 @@ export interface LocationControlSchema extends FormBaseControlSchema {
|
||||
* 有的地图需要设置 ak 信息
|
||||
*/
|
||||
ak?: string;
|
||||
|
||||
/**
|
||||
* 是否自动选中当前地理位置
|
||||
*/
|
||||
autoSelectCurrentLoc?: boolean;
|
||||
|
||||
/**
|
||||
* 是否限制只能选中当前地理位置
|
||||
* 备注:可用于充当定位组件,只允许选择当前位置
|
||||
*/
|
||||
onlySelectCurrentLoc?: boolean;
|
||||
|
||||
/**
|
||||
* 开启只读模式后的占位提示,默认为“点击获取位置信息”
|
||||
* 备注:区分下现有的placeholder(“请选择位置”)
|
||||
*/
|
||||
getLocationPlaceholder?: string;
|
||||
}
|
||||
|
||||
export interface LocationControlProps
|
||||
@ -51,33 +68,6 @@ export class LocationControl extends React.Component<LocationControlProps> {
|
||||
coordinatesType: 'bd09'
|
||||
};
|
||||
domRef: React.RefObject<HTMLDivElement> = React.createRef();
|
||||
state = {
|
||||
isOpened: false
|
||||
};
|
||||
|
||||
@autobind
|
||||
close() {
|
||||
this.setState({
|
||||
isOpened: false
|
||||
});
|
||||
}
|
||||
|
||||
@autobind
|
||||
open() {
|
||||
this.setState({
|
||||
isOpened: true
|
||||
});
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleClick() {
|
||||
this.state.isOpened ? this.close() : this.open();
|
||||
}
|
||||
|
||||
@autobind
|
||||
getParent() {
|
||||
return this.domRef.current?.parentElement;
|
||||
}
|
||||
|
||||
@autobind
|
||||
getTarget() {
|
||||
@ -85,14 +75,7 @@ export class LocationControl extends React.Component<LocationControlProps> {
|
||||
}
|
||||
|
||||
renderStatic(displayValue = '-') {
|
||||
const {
|
||||
classnames: cx,
|
||||
value,
|
||||
vendor,
|
||||
ak,
|
||||
coordinatesType,
|
||||
popOverContainer
|
||||
} = this.props;
|
||||
const {classnames: cx, value} = this.props;
|
||||
const __ = this.props.translate;
|
||||
|
||||
if (!value) {
|
||||
@ -107,35 +90,6 @@ export class LocationControl extends React.Component<LocationControlProps> {
|
||||
ref={this.domRef}
|
||||
>
|
||||
<span>{value.address}</span>
|
||||
<a
|
||||
className={cx('LocationPicker-toggler', 'ml-1')}
|
||||
onClick={this.handleClick}
|
||||
>
|
||||
<Icon icon="location" className="icon" />
|
||||
</a>
|
||||
<Overlay
|
||||
target={this.getTarget}
|
||||
container={popOverContainer || this.getParent}
|
||||
rootClose={false}
|
||||
show={this.state.isOpened}
|
||||
>
|
||||
<PopOver
|
||||
className={cx('LocationPicker-popover')}
|
||||
onHide={this.close}
|
||||
overlay
|
||||
style={{width: this.getTarget()?.offsetWidth}}
|
||||
>
|
||||
{vendor === 'baidu' ? (
|
||||
<BaiduMapPicker
|
||||
ak={ak}
|
||||
value={value}
|
||||
coordinatesType={coordinatesType}
|
||||
/>
|
||||
) : (
|
||||
<Alert2>{__('{{vendor}} 地图控件不支持', {vendor})}</Alert2>
|
||||
)}
|
||||
</PopOver>
|
||||
</Overlay>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
import React from 'react';
|
||||
import toString from 'lodash/toString';
|
||||
import {getPropValue, FormControlProps} from 'amis-core';
|
||||
import {ErrorBoundary} from 'react-error-boundary';
|
||||
import {ErrorBoundary} from 'amis-core';
|
||||
|
||||
function renderCommonStatic(props: any, defaultValue: string) {
|
||||
const {type, render, staticSchema} = props;
|
||||
@ -135,12 +134,20 @@ export function supportStatic<T extends FormControlProps>() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cx(`${ns}Form-static`, className)}>
|
||||
<ErrorBoundary fallback={<>{toString(body)}</>}>
|
||||
{body}
|
||||
</ErrorBoundary>
|
||||
<ErrorBoundary
|
||||
customErrorMsg={`拦截到${props.$schema.type}渲染错误,当前组件schema: ${props.$schema}`}
|
||||
fallback={() => {
|
||||
return (
|
||||
<div className="renderer-error-boundary">
|
||||
{props.$schema?.type}
|
||||
渲染发生错误,详细错误信息请查看控制台输出。
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
>
|
||||
<div className={cx(`${ns}Form-static`, className)}>{body}</div>
|
||||
</ErrorBoundary>
|
||||
);
|
||||
}
|
||||
|
||||
return original.apply(this, args);
|
||||
|
@ -6,11 +6,13 @@ import {
|
||||
resolveEventData
|
||||
} from 'amis-core';
|
||||
import {Icon, Switch} from 'amis-ui';
|
||||
import {createObject, autobind, isObject} from 'amis-core';
|
||||
import {autobind, isObject} from 'amis-core';
|
||||
import {IconSchema} from '../Icon';
|
||||
import {FormBaseControlSchema} from '../../Schema';
|
||||
import {supportStatic} from './StaticHoc';
|
||||
|
||||
import type {SpinnerExtraProps} from 'amis-ui';
|
||||
|
||||
/**
|
||||
* Switch
|
||||
* 文档:https://aisuda.bce.baidu.com/amis/zh-CN/components/form/switch
|
||||
@ -49,13 +51,17 @@ export interface SwitchControlSchema extends FormBaseControlSchema {
|
||||
|
||||
/** 开关尺寸 */
|
||||
size?: 'sm' | 'md';
|
||||
|
||||
/** 是否处于加载状态 */
|
||||
loading?: boolean;
|
||||
}
|
||||
|
||||
export interface SwitchProps extends FormControlProps {
|
||||
export interface SwitchProps extends FormControlProps, SpinnerExtraProps {
|
||||
option?: string;
|
||||
trueValue?: any;
|
||||
falseValue?: any;
|
||||
size?: 'sm';
|
||||
loading?: boolean;
|
||||
}
|
||||
|
||||
export type SwitchRendererEvent = 'change';
|
||||
@ -129,7 +135,9 @@ export default class SwitchControl extends React.Component<SwitchProps, any> {
|
||||
trueValue,
|
||||
falseValue,
|
||||
onChange,
|
||||
disabled
|
||||
disabled,
|
||||
loading,
|
||||
loadingConfig
|
||||
} = this.props;
|
||||
|
||||
const {on, off} = this.getResult();
|
||||
@ -147,6 +155,8 @@ export default class SwitchControl extends React.Component<SwitchProps, any> {
|
||||
disabled={disabled}
|
||||
onChange={this.handleChange}
|
||||
size={size as any}
|
||||
loading={loading}
|
||||
loadingConfig={loadingConfig}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
@ -30,7 +30,10 @@ function ItemActionsWrapper(props: ItemActionsProps) {
|
||||
}
|
||||
const rect = dom.getBoundingClientRect();
|
||||
const height = rect.height;
|
||||
const top = rect.top - frame.getBoundingClientRect().top;
|
||||
const top =
|
||||
rect.top -
|
||||
frame.getBoundingClientRect().top +
|
||||
parseInt(getComputedStyle(frame)['marginTop'], 10);
|
||||
divRef.current!.style.cssText += `top: ${top}px;height: ${height}px;`;
|
||||
}, [store.hoverRow?.id]);
|
||||
|
||||
|
@ -1591,6 +1591,10 @@ export default class Table extends React.Component<TableProps, object> {
|
||||
|
||||
document.addEventListener('mousemove', this.handleColResizeMouseMove);
|
||||
document.addEventListener('mouseup', this.handleColResizeMouseUp);
|
||||
|
||||
// 防止选中文本
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
// 垂直线拖拽移动
|
||||
@ -1760,8 +1764,6 @@ export default class Table extends React.Component<TableProps, object> {
|
||||
store,
|
||||
query,
|
||||
onQuery,
|
||||
multiple,
|
||||
env,
|
||||
render,
|
||||
classPrefix: ns,
|
||||
resizable,
|
||||
@ -1805,7 +1807,7 @@ export default class Table extends React.Component<TableProps, object> {
|
||||
style={style}
|
||||
className={cx(column.pristine.className, stickyClassName)}
|
||||
>
|
||||
{store.rows.length && multiple ? (
|
||||
{store.rows.length && store.multiple ? (
|
||||
<Checkbox
|
||||
classPrefix={ns}
|
||||
partial={store.someChecked && !store.allChecked}
|
||||
@ -2038,11 +2040,8 @@ export default class Table extends React.Component<TableProps, object> {
|
||||
const {
|
||||
render,
|
||||
store,
|
||||
multiple,
|
||||
classPrefix: ns,
|
||||
classnames: cx,
|
||||
checkOnItemClick,
|
||||
popOverContainer,
|
||||
canAccessSuperData,
|
||||
itemBadge,
|
||||
translate
|
||||
@ -2058,7 +2057,7 @@ export default class Table extends React.Component<TableProps, object> {
|
||||
ignoreDrag={ignoreDrag}
|
||||
render={render}
|
||||
store={store}
|
||||
multiple={multiple}
|
||||
multiple={store.multiple}
|
||||
canAccessSuperData={canAccessSuperData}
|
||||
classnames={cx}
|
||||
classPrefix={ns}
|
||||
|
Loading…
Reference in New Issue
Block a user