feat:表达式编辑器支持变量为函数和表达式&editor导出上下文变量获取方法

This commit is contained in:
lvxiaojiao 2023-06-27 18:59:26 +08:00
parent 4beeaca727
commit 259f1cc93c
10 changed files with 135 additions and 111 deletions

View File

@ -11,6 +11,8 @@ import type {Schema} from 'amis';
import type {SchemaObject} from 'amis'; import type {SchemaObject} from 'amis';
import {assign, cloneDeep} from 'lodash'; import {assign, cloneDeep} from 'lodash';
import {getGlobalData} from 'amis-theme-editor-helper'; import {getGlobalData} from 'amis-theme-editor-helper';
import {isExpression, resolveVariableAndFilter} from 'amis-core';
import type {VariableItem} from 'amis-ui';
const { const {
guid, guid,
@ -1132,3 +1134,90 @@ export function deleteThemeConfigData(data: any) {
return schemaData; return schemaData;
} }
/**
* amis数据域中取变量数据
* @param node
* @param manager
* @returns
*/
export async function resolveVariablesFromScope(node: any, manager: any) {
await manager?.getContextSchemas(node);
// 获取当前组件内相关变量,如表单、增删改查
const dataPropsAsOptions: VariableItem[] = updateComponentContext(
(await manager?.dataSchema?.getDataPropsAsOptions()) ?? []
);
const variables: VariableItem[] =
manager?.variableManager?.getVariableFormulaOptions() || [];
return [...dataPropsAsOptions, ...variables].filter(
(item: any) => item.children?.length
);
}
/**
* props & amis数据域 variables
* @param that this
**/
export async function getVariables(that: any) {
let variablesArr: any[] = [];
const {variables, requiredDataPropsVariables} = that.props;
if (!variables || requiredDataPropsVariables) {
// 从amis数据域中取变量数据
const {node, manager} = that.props.formProps || that.props;
let vars = await resolveVariablesFromScope(node, manager);
if (Array.isArray(vars)) {
if (!that.isUnmount) {
variablesArr = vars;
}
}
}
if (variables) {
if (Array.isArray(variables)) {
variablesArr = [...variables, ...variablesArr];
} else if (typeof variables === 'function') {
variablesArr = [...variables(that), ...variablesArr];
} else if (isExpression(variables)) {
variablesArr = [
...resolveVariableAndFilter(
that.props.variables as any,
that.props.data,
'| raw'
),
...variablesArr
];
}
}
// 如果存在应用语言类型,则进行翻译
if (that.appLocale && that.appCorpusData) {
return translateSchema(variablesArr, that.appCorpusData);
}
return variablesArr;
}
/**
* label为带层级说明
* @param variables
* @returns
*/
export const updateComponentContext = (variables: any[]) => {
const items = [...variables];
const idx = items.findIndex(item => item.label === '组件上下文');
if (~idx) {
items.splice(idx, 1, {
...items[idx],
children: items[idx].children.map((child: any, index: number) => ({
...child,
label:
index === 0
? `当前数据域${child.label ? '(' + child.label + ')' : ''}`
: `${index}${child.label ? '(' + child.label + ')' : ''}`
}))
});
}
return items;
};

View File

@ -8,9 +8,9 @@ import cx from 'classnames';
import {FormItem, Button, Icon, PickerContainer} from 'amis'; import {FormItem, Button, Icon, PickerContainer} from 'amis';
import {FormulaEditor} from 'amis-ui'; import {FormulaEditor} from 'amis-ui';
import type {VariableItem} from 'amis-ui'; import type {VariableItem} from 'amis-ui';
import {getVariables} from './textarea-formula/utils';
import {renderFormulaValue} from './FormulaControl'; import {renderFormulaValue} from './FormulaControl';
import {reaction} from 'mobx'; import {reaction} from 'mobx';
import {getVariables} from 'amis-editor-core';
interface ExpressionFormulaControlProps extends FormControlProps { interface ExpressionFormulaControlProps extends FormControlProps {
/** /**

View File

@ -3,16 +3,12 @@
*/ */
import React from 'react'; import React from 'react';
import debounce from 'lodash/debounce';
import uniqBy from 'lodash/uniqBy';
import isNumber from 'lodash/isNumber'; import isNumber from 'lodash/isNumber';
import isBoolean from 'lodash/isBoolean'; import isBoolean from 'lodash/isBoolean';
import isPlainObject from 'lodash/isPlainObject'; import isPlainObject from 'lodash/isPlainObject';
import isArray from 'lodash/isArray'; import isArray from 'lodash/isArray';
import isString from 'lodash/isString'; import isString from 'lodash/isString';
import isEqual from 'lodash/isEqual';
import omit from 'lodash/omit'; import omit from 'lodash/omit';
import last from 'lodash/last';
import cx from 'classnames'; import cx from 'classnames';
import { import {
FormItem, FormItem,
@ -34,11 +30,11 @@ import type {
VariableItem, VariableItem,
FuncGroup FuncGroup
} from 'amis-ui/lib/components/formula/Editor'; } from 'amis-ui/lib/components/formula/Editor';
import {dataMapping, FormControlProps} from 'amis-core'; import {FormControlProps} from 'amis-core';
import type {BaseEventContext} from 'amis-editor-core'; import type {BaseEventContext} from 'amis-editor-core';
import {EditorManager} from 'amis-editor-core'; import {EditorManager} from 'amis-editor-core';
import {reaction} from 'mobx'; import {reaction} from 'mobx';
import {getVariables} from './textarea-formula/utils'; import {getVariables} from 'amis-editor-core';
export enum FormulaDateType { export enum FormulaDateType {
NotDate, // 不是时间类 NotDate, // 不是时间类

View File

@ -10,11 +10,11 @@ import type {VariableItem, CodeMirror} from 'amis-ui';
import {Icon, Button, FormItem, TooltipWrapper} from 'amis'; import {Icon, Button, FormItem, TooltipWrapper} from 'amis';
import {autobind, FormControlProps} from 'amis-core'; import {autobind, FormControlProps} from 'amis-core';
import {FormulaPlugin, editorFactory} from './textarea-formula/plugin'; import {FormulaPlugin, editorFactory} from './textarea-formula/plugin';
import {getVariables} from './textarea-formula/utils';
import {renderFormulaValue} from './FormulaControl'; import {renderFormulaValue} from './FormulaControl';
import FormulaPicker, { import FormulaPicker, {
CustomFormulaPickerProps CustomFormulaPickerProps
} from './textarea-formula/FormulaPicker'; } from './textarea-formula/FormulaPicker';
import {getVariables} from 'amis-editor-core';
export interface TplFormulaControlProps extends FormControlProps { export interface TplFormulaControlProps extends FormControlProps {
/** /**

View File

@ -41,7 +41,7 @@ export * from './helper';
import {i18n as _i18n} from 'i18n-runtime'; import {i18n as _i18n} from 'i18n-runtime';
import type {VariableItem} from 'amis-ui/lib/components/formula/Editor'; import type {VariableItem} from 'amis-ui/lib/components/formula/Editor';
import {reaction} from 'mobx'; import {reaction} from 'mobx';
import {updateComponentContext} from '../../util'; import {updateComponentContext} from 'amis-editor-core';
interface EventControlProps extends FormControlProps { interface EventControlProps extends FormControlProps {
actions: PluginActions; // 组件的动作列表 actions: PluginActions; // 组件的动作列表
@ -504,7 +504,12 @@ export class EventControl extends React.Component<
// 编辑的时候只能拿到当前动作前面动作的事件变量以及当前动作事件 // 编辑的时候只能拿到当前动作前面动作的事件变量以及当前动作事件
if (data.type === 'update') { if (data.type === 'update') {
actions = actions.slice(0, data.actionData!.actionIndex !== undefined ? data.actionData!.actionIndex + 1 : 0); actions = actions.slice(
0,
data.actionData!.actionIndex !== undefined
? data.actionData!.actionIndex + 1
: 0
);
} }
let jsonSchema = {...(eventConfig?.dataSchema?.[0] ?? {})}; let jsonSchema = {...(eventConfig?.dataSchema?.[0] ?? {})};

View File

@ -11,9 +11,9 @@ import type {VariableItem, CodeMirror} from 'amis-ui';
import {FormulaPlugin, editorFactory} from './plugin'; import {FormulaPlugin, editorFactory} from './plugin';
import FormulaPicker, {CustomFormulaPickerProps} from './FormulaPicker'; import FormulaPicker, {CustomFormulaPickerProps} from './FormulaPicker';
import {getVariables} from './utils';
import {reaction} from 'mobx'; import {reaction} from 'mobx';
import {renderFormulaValue} from '../FormulaControl'; import {renderFormulaValue} from '../FormulaControl';
import {getVariables} from 'amis-editor-core';
export interface AdditionalMenuClickOpts { export interface AdditionalMenuClickOpts {
/** /**

View File

@ -1,67 +0,0 @@
import {isExpression, resolveVariableAndFilter} from 'amis-core';
import {translateSchema} from 'amis-editor-core';
import type {VariableItem} from 'amis-ui/lib/components/formula/Editor';
import {updateComponentContext} from '../../util';
/**
* amis数据域中取变量数据
* @param node
* @param manager
* @returns
*/
export async function resolveVariablesFromScope(node: any, manager: any) {
await manager?.getContextSchemas(node);
// 获取当前组件内相关变量,如表单、增删改查
const dataPropsAsOptions: VariableItem[] = updateComponentContext(
(await manager?.dataSchema?.getDataPropsAsOptions()) ?? []
);
const variables: VariableItem[] =
manager?.variableManager?.getVariableFormulaOptions() || [];
return [...dataPropsAsOptions, ...variables].filter(
(item: any) => item.children?.length
);
}
/**
* props & amis数据域 variables
* @param that this
**/
export async function getVariables(that: any) {
let variablesArr: any[] = [];
const {variables, requiredDataPropsVariables} = that.props;
if (!variables || requiredDataPropsVariables) {
// 从amis数据域中取变量数据
const {node, manager} = that.props.formProps || that.props;
let vars = await resolveVariablesFromScope(node, manager);
if (Array.isArray(vars)) {
if (!that.isUnmount) {
variablesArr = vars;
}
}
}
if (variables) {
if (Array.isArray(variables)) {
variablesArr = [...variables, ...variablesArr];
} else if (typeof variables === 'function') {
variablesArr = [...variables(that), ...variablesArr];
} else if (isExpression(variables)) {
variablesArr = [
...resolveVariableAndFilter(
that.props.variables as any,
that.props.data,
'| raw'
),
...variablesArr
];
}
}
// 如果存在应用语言类型,则进行翻译
if (that.appLocale && that.appCorpusData) {
return translateSchema(variablesArr, that.appCorpusData);
}
return variablesArr;
}

View File

@ -42,26 +42,3 @@ export const schemaToArray = (value: any) => {
export const schemaArrayFormat = (value: any) => { export const schemaArrayFormat = (value: any) => {
return value && Array.isArray(value) && value.length === 1 ? value[0] : value; return value && Array.isArray(value) && value.length === 1 ? value[0] : value;
}; };
/**
* label为带层级说明
* @param variables
* @returns
*/
export const updateComponentContext = (variables: any[]) => {
const items = [...variables];
const idx = items.findIndex(item => item.label === '组件上下文');
if (~idx) {
items.splice(idx, 1, {
...items[idx],
children: items[idx].children.map((child: any, index: number) => ({
...child,
label:
index === 0
? `当前数据域${child.label ? '(' + child.label + ')' : ''}`
: `${index}${child.label ? '(' + child.label + ')' : ''}`
}))
});
}
return items;
};

View File

@ -243,7 +243,7 @@ export class FormulaEditor extends React.Component<
componentDidMount(): void { componentDidMount(): void {
const {variables} = this.props; const {variables} = this.props;
this.normalizeVariables(variables); this.normalizeVariables(variables as VariableItem[]);
} }
componentDidUpdate( componentDidUpdate(
@ -252,7 +252,7 @@ export class FormulaEditor extends React.Component<
snapshot?: any snapshot?: any
): void { ): void {
if (prevProps.variables !== this.props.variables) { if (prevProps.variables !== this.props.variables) {
this.normalizeVariables(this.props.variables); this.normalizeVariables(this.props.variables as VariableItem[]);
} }
} }

View File

@ -1,4 +1,8 @@
import {uncontrollable} from 'amis-core'; import {
isExpression,
resolveVariableAndFilterForAsync,
uncontrollable
} from 'amis-core';
import React from 'react'; import React from 'react';
import { import {
FormulaEditor, FormulaEditor,
@ -23,7 +27,8 @@ import Modal from '../Modal';
import PopUp from '../PopUp'; import PopUp from '../PopUp';
import {isMobile} from 'amis-core'; import {isMobile} from 'amis-core';
export interface FormulaPickerProps extends FormulaEditorProps { export interface FormulaPickerProps
extends Omit<FormulaEditorProps, 'variables'> {
// 新的属性? // 新的属性?
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'full'; size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'full';
@ -124,7 +129,13 @@ export interface FormulaPickerProps extends FormulaEditorProps {
onRef?: (node: any) => void; onRef?: (node: any) => void;
popOverContainer?: any; popOverContainer?: any;
useMobileUI?: boolean; useMobileUI?: boolean;
variables?:
| Array<VariableItem>
| string
| ((props: any) => Array<VariableItem>);
} }
export interface FormulaPickerState { export interface FormulaPickerState {
@ -155,7 +166,8 @@ export class FormulaPicker extends React.Component<
isOpened: false, isOpened: false,
value: this.props.value!, value: this.props.value!,
editorValue: this.value2EditorValue(this.props), editorValue: this.value2EditorValue(this.props),
isError: false isError: false,
variables: Array.isArray(props.variables) ? props.variables : []
}; };
} }
@ -254,6 +266,19 @@ export class FormulaPicker extends React.Component<
@autobind @autobind
async handleClick() { async handleClick() {
const {variables, data} = this.props;
if (typeof variables === 'function') {
const list = await variables(this.props);
this.setState({variables: list});
} else if (typeof variables === 'string' && isExpression(variables)) {
const result = await resolveVariableAndFilterForAsync(
variables,
data,
'|raw'
);
this.setState({variables: result});
}
const state = { const state = {
...(await this.props.onPickerOpen?.(this.props)), ...(await this.props.onPickerOpen?.(this.props)),
editorValue: this.value2EditorValue(this.props), editorValue: this.value2EditorValue(this.props),
@ -328,7 +353,6 @@ export class FormulaPicker extends React.Component<
icon, icon,
title, title,
clearable, clearable,
variables,
functions, functions,
children, children,
variableMode, variableMode,
@ -405,7 +429,7 @@ export class FormulaPicker extends React.Component<
? void 0 ? void 0
: FormulaEditor.highlightValue( : FormulaEditor.highlightValue(
value, value,
variables!, this.state.variables!,
this.props.evalMode this.props.evalMode
) )
} }
@ -448,7 +472,7 @@ export class FormulaPicker extends React.Component<
? void 0 ? void 0
: FormulaEditor.highlightValue( : FormulaEditor.highlightValue(
value, value,
variables!, this.state.variables!,
this.props.evalMode this.props.evalMode
) )
} }
@ -485,7 +509,7 @@ export class FormulaPicker extends React.Component<
<Editor <Editor
{...rest} {...rest}
evalMode={mixedMode ? true : evalMode} evalMode={mixedMode ? true : evalMode}
variables={this.state.variables ?? variables} variables={this.state.variables}
functions={this.state.functions ?? functions} functions={this.state.functions ?? functions}
variableMode={this.state.variableMode ?? variableMode} variableMode={this.state.variableMode ?? variableMode}
value={editorValue} value={editorValue}
@ -516,7 +540,7 @@ export class FormulaPicker extends React.Component<
<Editor <Editor
{...rest} {...rest}
evalMode={mixedMode ? true : evalMode} evalMode={mixedMode ? true : evalMode}
variables={this.state.variables ?? variables} variables={this.state.variables}
functions={this.state.functions ?? functions} functions={this.state.functions ?? functions}
variableMode={this.state.variableMode ?? variableMode} variableMode={this.state.variableMode ?? variableMode}
value={editorValue} value={editorValue}