mirror of
https://gitee.com/baidu/amis.git
synced 2024-11-29 18:48:45 +08:00
feat: 弹窗参数映射支持公式 (#9960)
This commit is contained in:
parent
067b82fa51
commit
e64b239dd3
@ -115,6 +115,139 @@ order: 61
|
||||
}
|
||||
```
|
||||
|
||||
## 搭配公式使用
|
||||
|
||||
> 6.4.0 及以上版本
|
||||
|
||||
通过配置 `formula` 属性,可以配合公式使用。
|
||||
|
||||
```schema: scope="body"
|
||||
{
|
||||
"type": "form",
|
||||
"api": "/api/mock2/form/saveForm",
|
||||
debug: true,
|
||||
"body": [
|
||||
{
|
||||
"type": "json-schema",
|
||||
"name": "value",
|
||||
"label": "字段值",
|
||||
"schema": {
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
required: ['id', 'name'],
|
||||
properties: {
|
||||
id: {
|
||||
type: 'number',
|
||||
title: 'ID'
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
title: '名称'
|
||||
},
|
||||
description: {
|
||||
type: 'string',
|
||||
title: '描述'
|
||||
},
|
||||
date: {
|
||||
type: 'object',
|
||||
title: '日期',
|
||||
additionalProperties: false,
|
||||
required: ['year', 'month', 'day'],
|
||||
properties: {
|
||||
year: {
|
||||
type: 'number',
|
||||
title: '年'
|
||||
},
|
||||
month: {
|
||||
type: 'number',
|
||||
title: '月'
|
||||
},
|
||||
day: {
|
||||
type: 'number',
|
||||
title: '日'
|
||||
}
|
||||
}
|
||||
},
|
||||
tag: {
|
||||
type: 'array',
|
||||
title: '个人标签',
|
||||
items: {
|
||||
type: 'string'
|
||||
},
|
||||
minContains: 2,
|
||||
maxContains: 10
|
||||
}
|
||||
}
|
||||
},
|
||||
"formula": {
|
||||
"mode":"input-group",
|
||||
"mixedMode": true,
|
||||
"variables": [
|
||||
{
|
||||
"label": "表单字段",
|
||||
"children": [
|
||||
{
|
||||
"label": "文章名",
|
||||
"value": "name",
|
||||
"tag": "文本"
|
||||
},
|
||||
{
|
||||
"label": "作者",
|
||||
"value": "author",
|
||||
"tag": "文本"
|
||||
},
|
||||
{
|
||||
"label": "售价",
|
||||
"value": "price",
|
||||
"tag": "数字"
|
||||
},
|
||||
{
|
||||
"label": "出版时间",
|
||||
"value": "time",
|
||||
"tag": "时间"
|
||||
},
|
||||
{
|
||||
"label": "版本号",
|
||||
"value": "version",
|
||||
"tag": "数字"
|
||||
},
|
||||
{
|
||||
"label": "出版社",
|
||||
"value": "publisher",
|
||||
"tag": "文本"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "流程字段",
|
||||
"children": [
|
||||
{
|
||||
"label": "联系电话",
|
||||
"value": "telphone"
|
||||
},
|
||||
{
|
||||
"label": "地址",
|
||||
"value": "addr"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "长文本测试分类长文本测试分类长文本测试分类长文本测试分类",
|
||||
"children": [
|
||||
{
|
||||
"label": "这是一段测试长文本这是一段测试长文本这是一段测试长文本",
|
||||
"value": "longtext",
|
||||
"tag": "文本"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 远程获取 schema
|
||||
|
||||
```schema: scope="body"
|
||||
|
@ -6,6 +6,7 @@ import {
|
||||
JSONPipeOut,
|
||||
JSONUpdate,
|
||||
addModal,
|
||||
getVariables,
|
||||
modalsToDefinitions
|
||||
} from 'amis-editor-core';
|
||||
import React from 'react';
|
||||
@ -57,7 +58,9 @@ function DialogActionPanel({
|
||||
onBulkChange,
|
||||
node,
|
||||
addHook,
|
||||
subscribeSchemaSubmit
|
||||
subscribeSchemaSubmit,
|
||||
appLocale,
|
||||
appCorpusData
|
||||
}: DialogActionPanelProps) {
|
||||
const eventKey = data.eventKey;
|
||||
|
||||
@ -609,6 +612,17 @@ function DialogActionPanel({
|
||||
);
|
||||
}, []);
|
||||
|
||||
const formula: any = React.useMemo(() => {
|
||||
return {
|
||||
variables: () =>
|
||||
getVariables({
|
||||
props: {node, manager},
|
||||
appLocale,
|
||||
appCorpusData
|
||||
})
|
||||
};
|
||||
}, [node, manager]);
|
||||
|
||||
return (
|
||||
<div className={cx('ae-DialogActionPanel')}>
|
||||
<FormField
|
||||
@ -686,6 +700,7 @@ function DialogActionPanel({
|
||||
onChange={handleDataChange}
|
||||
schema={JSONPipeOut(currentModal.modal.inputParams)}
|
||||
addButtonText="添加参数"
|
||||
formula={formula}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
|
@ -230,6 +230,7 @@ export function withRemoteConfig<P = any>(
|
||||
super(props);
|
||||
|
||||
this.setConfig = this.setConfig.bind(this);
|
||||
this.childRef = this.childRef.bind(this);
|
||||
props.store.setComponent(this);
|
||||
this.deferLoadConfig = this.deferLoadConfig.bind(this);
|
||||
props.remoteConfigRef?.(this);
|
||||
@ -401,6 +402,20 @@ export function withRemoteConfig<P = any>(
|
||||
ret2 && store.setConfig(ret2, config, 'after-defer-load');
|
||||
}
|
||||
|
||||
ref: any;
|
||||
|
||||
childRef(ref: any) {
|
||||
while (ref && ref.getWrappedInstance) {
|
||||
ref = ref.getWrappedInstance();
|
||||
}
|
||||
|
||||
this.ref = ref;
|
||||
}
|
||||
|
||||
getWrappedInstance() {
|
||||
return this.ref;
|
||||
}
|
||||
|
||||
render() {
|
||||
const store = this.props.store;
|
||||
const env: RendererEnv =
|
||||
@ -412,6 +427,12 @@ export function withRemoteConfig<P = any>(
|
||||
updateConfig: this.setConfig
|
||||
};
|
||||
const {remoteConfigRef, autoComplete, ...rest} = this.props;
|
||||
const refConfig =
|
||||
ComposedComponent.prototype?.isReactComponent ||
|
||||
(ComposedComponent as any).$$typeof ===
|
||||
Symbol.for('react.forward_ref')
|
||||
? {ref: this.childRef}
|
||||
: {forwardedRef: this.childRef};
|
||||
|
||||
return (
|
||||
<ComposedComponent
|
||||
@ -425,6 +446,7 @@ export function withRemoteConfig<P = any>(
|
||||
{...(config.injectedPropsFilter
|
||||
? config.injectedPropsFilter(injectedProps, this.props)
|
||||
: injectedProps)}
|
||||
{...refConfig}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import {guid} from 'amis-core';
|
||||
import Button from '../Button';
|
||||
import {Icon} from '../icons';
|
||||
import type {InputJSONSchemaItemProps} from './index';
|
||||
import {InputJSONSchemaItem} from './Item';
|
||||
import InputJSONSchemaItem from './Item';
|
||||
|
||||
type JSONSchemaArrayMember = {
|
||||
key: string;
|
||||
|
@ -4,16 +4,58 @@ import NumberInput from '../NumberInput';
|
||||
import Switch from '../Switch';
|
||||
import {InputJSONSchemaArray} from './Array';
|
||||
import type {InputJSONSchemaItemProps} from './index';
|
||||
import {InputJSONSchemaObject} from './Object';
|
||||
import InputJSONSchemaObject from './Object';
|
||||
import {FormulaPicker} from '../formula/Picker';
|
||||
|
||||
export function InputJSONSchemaItem(props: InputJSONSchemaItemProps, ref: any) {
|
||||
const childRef = React.useRef<any>();
|
||||
React.useImperativeHandle(ref, () => {
|
||||
return {
|
||||
validate() {
|
||||
return childRef.current?.validate();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
export function InputJSONSchemaItem(props: InputJSONSchemaItemProps) {
|
||||
const schema = props.schema;
|
||||
const formua = props.formula;
|
||||
if (schema.type === 'object') {
|
||||
return <InputJSONSchemaObject {...props} />;
|
||||
return <InputJSONSchemaObject {...props} ref={childRef} />;
|
||||
} else if (schema.type === 'array') {
|
||||
return <InputJSONSchemaArray {...props} />;
|
||||
} else if (props.renderValue) {
|
||||
return props.renderValue(props.value, props.onChange, schema, props);
|
||||
} else if (formua) {
|
||||
const inputSettings = React.useMemo(() => {
|
||||
const inputSettings: any = {
|
||||
...formua.inputSettings
|
||||
};
|
||||
|
||||
if (schema.type === 'number' || schema.type === 'integer') {
|
||||
inputSettings.type = 'number';
|
||||
} else if (schema.type === 'boolean') {
|
||||
inputSettings.type = 'boolean';
|
||||
}
|
||||
return inputSettings;
|
||||
}, [formua.inputSettings, schema.type]);
|
||||
return (
|
||||
<FormulaPicker
|
||||
mode="input-group"
|
||||
mixedMode={true}
|
||||
{...formua}
|
||||
inputSettings={inputSettings}
|
||||
value={props.value ?? schema.default}
|
||||
onChange={props.onChange}
|
||||
className={props.className}
|
||||
disabled={props.disabled}
|
||||
placeholder={props.placeholder}
|
||||
theme={props.theme}
|
||||
classPrefix={props.classPrefix}
|
||||
classnames={props.classnames}
|
||||
translate={props.translate}
|
||||
locale={props.locale}
|
||||
/>
|
||||
);
|
||||
} else if (schema.type == 'number') {
|
||||
return (
|
||||
<NumberInput
|
||||
@ -55,3 +97,5 @@ export function InputJSONSchemaItem(props: InputJSONSchemaItemProps) {
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.forwardRef(InputJSONSchemaItem);
|
||||
|
@ -6,7 +6,7 @@ import InputBox from '../InputBox';
|
||||
import InputBoxWithSuggestion from '../InputBoxWithSuggestion';
|
||||
import Select from '../Select';
|
||||
import type {InputJSONSchemaItemProps} from './index';
|
||||
import {InputJSONSchemaItem} from './Item';
|
||||
import InputJSONSchemaItem from './Item';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
|
||||
type JSONSchemaObjectMember = {
|
||||
@ -18,7 +18,10 @@ type JSONSchemaObjectMember = {
|
||||
required?: boolean;
|
||||
value?: any;
|
||||
};
|
||||
export function InputJSONSchemaObject(props: InputJSONSchemaItemProps) {
|
||||
export function InputJSONSchemaObject(
|
||||
props: InputJSONSchemaItemProps,
|
||||
ref: any
|
||||
) {
|
||||
const {
|
||||
classnames: cx,
|
||||
value,
|
||||
@ -224,6 +227,16 @@ export function InputJSONSchemaObject(props: InputJSONSchemaItemProps) {
|
||||
);
|
||||
const allowInput = props.schema.additionalProperties !== false;
|
||||
|
||||
React.useImperativeHandle(ref, () => {
|
||||
return {
|
||||
validate(): any {
|
||||
if (membersRef.current?.some(m => m.invalid)) {
|
||||
return __('JSONSchema.key_invalid');
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
{collapsable ? (
|
||||
@ -382,3 +395,5 @@ export function InputJSONSchemaObject(props: InputJSONSchemaItemProps) {
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.forwardRef(InputJSONSchemaObject);
|
||||
|
@ -6,7 +6,8 @@ import {
|
||||
themeable,
|
||||
ThemeProps
|
||||
} from 'amis-core';
|
||||
import {InputJSONSchemaItem} from './Item';
|
||||
import InputJSONSchemaItem from './Item';
|
||||
import {FormulaPickerProps} from '../formula/Picker';
|
||||
|
||||
export interface InputJSONSchemaItemProps extends ThemeProps, LocaleProps {
|
||||
schema: JSONSchema & {
|
||||
@ -31,6 +32,7 @@ export interface InputJSONSchemaItemProps extends ThemeProps, LocaleProps {
|
||||
placeholder?: string;
|
||||
required?: boolean;
|
||||
addButtonText?: string;
|
||||
formula?: FormulaPickerProps;
|
||||
}
|
||||
|
||||
export interface InputJSONSchemaProps
|
||||
@ -38,13 +40,23 @@ export interface InputJSONSchemaProps
|
||||
schema?: any;
|
||||
}
|
||||
|
||||
function InputJSONSchema(props: InputJSONSchemaProps) {
|
||||
function InputJSONSchema(props: InputJSONSchemaProps, ref: any) {
|
||||
const schema = props.schema || {
|
||||
type: 'object',
|
||||
properties: {}
|
||||
};
|
||||
|
||||
return <InputJSONSchemaItem {...props} schema={schema} />;
|
||||
const childRef = React.useRef<any>();
|
||||
|
||||
React.useImperativeHandle(ref, () => {
|
||||
return {
|
||||
validate() {
|
||||
return childRef.current?.validate();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
return <InputJSONSchemaItem {...props} schema={schema} ref={childRef} />;
|
||||
}
|
||||
|
||||
export default themeable(localeable(InputJSONSchema));
|
||||
export default themeable(localeable(React.forwardRef(InputJSONSchema)));
|
||||
|
@ -433,6 +433,7 @@ register('de-DE', {
|
||||
'JSONSchema.array_items': 'Artikel',
|
||||
'JSONSchema.members': 'Mitglieder',
|
||||
'JSONSchema.key_duplicated': 'Schlüssel existiert bereits',
|
||||
'JSONSchema.key_invalid': 'Schlüssel ungültig',
|
||||
'TimeNow': 'Jetzt',
|
||||
'Steps.step': 'Schritt {{index}}',
|
||||
'FormulaInput.True': 'Treu',
|
||||
|
@ -415,6 +415,7 @@ register('en-US', {
|
||||
'JSONSchema.array_items': 'Items',
|
||||
'JSONSchema.members': 'Members',
|
||||
'JSONSchema.key_duplicated': 'Key already exists',
|
||||
'JSONSchema.key_invalid': 'Key invalid',
|
||||
'TimeNow': 'Now',
|
||||
'IconSelect.all': 'All',
|
||||
'IconSelect.choice': 'Icon selection',
|
||||
|
@ -409,6 +409,7 @@ register('zh-CN', {
|
||||
'JSONSchema.array_items': '成员类型',
|
||||
'JSONSchema.members': '成员',
|
||||
'JSONSchema.key_duplicated': '字段名已经存在',
|
||||
'JSONSchema.key_invalid': '字段名格式错误',
|
||||
'Required': '必填',
|
||||
'TimeNow': '此刻',
|
||||
'IconSelect.all': '全部',
|
||||
|
@ -99,6 +99,11 @@ export interface ConditionBuilderControlSchema extends FormBaseControlSchema {
|
||||
* 将字段输入控件变成公式编辑器。
|
||||
*/
|
||||
formula?: Omit<InputFormulaControlSchema, 'type'>;
|
||||
|
||||
/**
|
||||
* if 里面公式编辑器配置
|
||||
*/
|
||||
formulaForIf?: any;
|
||||
}
|
||||
|
||||
export interface ConditionBuilderProps
|
||||
|
@ -1,8 +1,9 @@
|
||||
import React from 'react';
|
||||
import {FormItem, FormControlProps, FormBaseControl} from 'amis-core';
|
||||
import {FormItem, FormControlProps, FormBaseControl, autobind} from 'amis-core';
|
||||
import {InputJSONSchema} from 'amis-ui';
|
||||
import {withRemoteConfig} from 'amis-ui';
|
||||
import {FormBaseControlSchema} from '../../Schema';
|
||||
import {InputFormulaControlSchema} from './InputFormula';
|
||||
|
||||
/**
|
||||
* JSON Schema
|
||||
@ -18,6 +19,11 @@ export interface JSONSchemaControlSchema extends FormBaseControlSchema {
|
||||
* json-schema 详情,支持关联上下文数据
|
||||
*/
|
||||
schema?: any;
|
||||
|
||||
/**
|
||||
* 将字段输入控件变成公式编辑器。
|
||||
*/
|
||||
formula?: Omit<InputFormulaControlSchema, 'type'>;
|
||||
}
|
||||
|
||||
export interface JSONSchemaProps
|
||||
@ -37,10 +43,24 @@ const EnhancedInputJSONSchema = withRemoteConfig({
|
||||
}
|
||||
})(InputJSONSchema as any);
|
||||
export default class JSONSchemaControl extends React.PureComponent<JSONSchemaProps> {
|
||||
control: any;
|
||||
|
||||
@autobind
|
||||
controlRef(ref: any) {
|
||||
while (ref?.getWrappedInstance) {
|
||||
ref = ref.getWrappedInstance();
|
||||
}
|
||||
this.control = ref;
|
||||
}
|
||||
|
||||
validate() {
|
||||
return this.control?.validate();
|
||||
}
|
||||
|
||||
render() {
|
||||
const {...rest} = this.props;
|
||||
|
||||
return <EnhancedInputJSONSchema {...rest} />;
|
||||
return <EnhancedInputJSONSchema {...rest} ref={this.controlRef} />;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user