mirror of
https://gitee.com/baidu/amis.git
synced 2024-12-02 03:58:07 +08:00
feat: 公式支持快捷变量支持
This commit is contained in:
parent
09e564e9e7
commit
0a436fb137
@ -4,7 +4,7 @@
|
||||
import {hasIcon, mapObject, utils} from 'amis';
|
||||
import type {PlainObject, Schema, SchemaNode} from 'amis';
|
||||
import {getGlobalData} from 'amis-theme-editor-helper';
|
||||
import {isExpression, resolveVariableAndFilter} from 'amis-core';
|
||||
import {filterTree, isExpression, resolveVariableAndFilter} from 'amis-core';
|
||||
import type {VariableItem} from 'amis-ui';
|
||||
import {isObservable, reaction} from 'mobx';
|
||||
import DeepDiff, {Diff} from 'deep-diff';
|
||||
@ -1362,65 +1362,78 @@ export async function getVariables(that: any) {
|
||||
return variablesArr;
|
||||
}
|
||||
|
||||
export async function getQuickVariables(
|
||||
that: any,
|
||||
resolver?: (vars: any[]) => any[]
|
||||
) {
|
||||
export async function getQuickVariables(that: any) {
|
||||
const {node, manager} = that.props.formProps || that.props;
|
||||
const selfName = that.props?.data?.name;
|
||||
const {quickVars, data} = that.props;
|
||||
const selfName = data?.name;
|
||||
await manager?.getContextSchemas(node);
|
||||
const options = await manager?.dataSchema?.getDataPropsAsOptions();
|
||||
if (Array.isArray(options)) {
|
||||
const vars = options.find(item => item.label === '组件上下文');
|
||||
if (vars?.children?.length) {
|
||||
// 获取当前层的变量
|
||||
const current: any[] = vars.children[0].children || [];
|
||||
const filterVars = current
|
||||
.filter(item => item.value !== selfName && item.schemaType)
|
||||
.map(item => {
|
||||
// 子表过滤成员那层
|
||||
if (item.type === 'array' && Array.isArray(item.children)) {
|
||||
if (item.children.length === 1) {
|
||||
const child = item.children[0];
|
||||
if (child.type === 'object' && child.disabled) {
|
||||
return {
|
||||
...item,
|
||||
children: child.children
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
return item;
|
||||
});
|
||||
|
||||
return resolver ? resolver(filterVars) : filterVars;
|
||||
}
|
||||
const curOptions = options.find(item => item.label === '组件上下文');
|
||||
return resolveQuickVariables(curOptions, quickVars, selfName);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
export function resolveQuickVariablesByType(
|
||||
variables: VariableItem[],
|
||||
quickVars?: VariableItem[]
|
||||
export function resolveQuickVariables(
|
||||
option: any,
|
||||
quickVars?: VariableItem[],
|
||||
selfName?: string
|
||||
) {
|
||||
if (!option?.children?.length) {
|
||||
return [];
|
||||
}
|
||||
const finalVars = [];
|
||||
const curOption = option.children[0];
|
||||
const superOption = option.children[1];
|
||||
const variables = (curOption.children || [])
|
||||
.filter((item: any) => item.value !== selfName && item.schemaType)
|
||||
.map((item: any) => {
|
||||
// 子表过滤成员那层
|
||||
if (item.type === 'array' && Array.isArray(item.children)) {
|
||||
if (item.children.length === 1) {
|
||||
const child = item.children[0];
|
||||
if (child.type === 'object' && child.disabled) {
|
||||
return {
|
||||
...item,
|
||||
children: child.children
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
return item;
|
||||
});
|
||||
if (superOption?.children?.length) {
|
||||
const superVars = superOption?.children.filter(
|
||||
(item: any) => item.schemaType && item.type !== 'array'
|
||||
);
|
||||
finalVars.push(...superVars);
|
||||
finalVars.push({
|
||||
label: curOption.label,
|
||||
children: variables
|
||||
});
|
||||
} else {
|
||||
finalVars.push(...variables);
|
||||
}
|
||||
|
||||
if (quickVars?.length) {
|
||||
const vars: VariableItem[] = [];
|
||||
vars.push({
|
||||
label: '快捷变量',
|
||||
children: quickVars
|
||||
});
|
||||
if (variables.length) {
|
||||
if (finalVars.length) {
|
||||
vars.push({
|
||||
label: '表单变量',
|
||||
children: variables
|
||||
children: finalVars
|
||||
});
|
||||
}
|
||||
|
||||
return vars;
|
||||
}
|
||||
|
||||
return variables;
|
||||
return finalVars;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -20,11 +20,7 @@ import FormulaPicker, {
|
||||
import {JSONPipeOut, autobind, translateSchema} from 'amis-editor-core';
|
||||
import {EditorManager} from 'amis-editor-core';
|
||||
import {reaction} from 'mobx';
|
||||
import {
|
||||
getVariables,
|
||||
getQuickVariables,
|
||||
resolveQuickVariablesByType
|
||||
} from 'amis-editor-core';
|
||||
import {getVariables, getQuickVariables} from 'amis-editor-core';
|
||||
|
||||
import type {BaseEventContext} from 'amis-editor-core';
|
||||
import type {VariableItem, FuncGroup} from 'amis-ui';
|
||||
@ -215,14 +211,11 @@ export default class FormulaControl extends React.Component<
|
||||
}
|
||||
);
|
||||
|
||||
const {valueType, quickVars} = this.props;
|
||||
const variables = await getVariables(this);
|
||||
const quickVariables = await getQuickVariables(this, items =>
|
||||
items.filter(item => item.schemaType === valueType)
|
||||
);
|
||||
const quickVariables = await getQuickVariables(this);
|
||||
this.setState({
|
||||
variables,
|
||||
quickVariables: resolveQuickVariablesByType(quickVariables, quickVars)
|
||||
quickVariables: this.filterQuickVariablesByType(quickVariables)
|
||||
});
|
||||
}
|
||||
|
||||
@ -236,6 +229,26 @@ export default class FormulaControl extends React.Component<
|
||||
this.buttonTarget = ref;
|
||||
}
|
||||
|
||||
@autobind
|
||||
filterQuickVariablesByType(variables: any[]) {
|
||||
const rendererSchema = this.getRendererSchemaFromProps();
|
||||
const filterVars = variables
|
||||
.map(item => {
|
||||
if (item.children) {
|
||||
item.children = item.children.filter(
|
||||
(i: any) => i.schemaType === rendererSchema.type
|
||||
);
|
||||
}
|
||||
return item;
|
||||
})
|
||||
.filter(
|
||||
item =>
|
||||
item.schemaType === rendererSchema.type ||
|
||||
(item.children && item.children?.length)
|
||||
);
|
||||
return filterVars;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 ${xx}(非 \${xx})替换成 \${xx}
|
||||
* 备注: 手动编辑时,自动处理掉 ${xx},避免识别成 公式表达式
|
||||
@ -664,6 +677,7 @@ export default class FormulaControl extends React.Component<
|
||||
data={quickVariables}
|
||||
onSelect={this.handleQuickVariableSelect}
|
||||
popOverContainer={popOverContainer}
|
||||
simplifyMemberOprs
|
||||
/>
|
||||
</ul>
|
||||
);
|
||||
|
@ -55,6 +55,11 @@ export interface TplFormulaControlProps extends FormControlProps {
|
||||
* 支付支持快捷变量
|
||||
*/
|
||||
quickVariables?: boolean;
|
||||
|
||||
/**
|
||||
* 额外的快捷变量
|
||||
*/
|
||||
quickVars?: Array<VariableItem>;
|
||||
}
|
||||
|
||||
interface TplFormulaControlState {
|
||||
@ -148,7 +153,10 @@ export class TplFormulaControl extends React.Component<
|
||||
|
||||
const variables = await getVariables(this);
|
||||
const quickVariables = await getQuickVariables(this);
|
||||
this.setState({variables, quickVariables});
|
||||
this.setState({
|
||||
variables,
|
||||
quickVariables
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
@ -474,6 +482,7 @@ export class TplFormulaControl extends React.Component<
|
||||
data={quickVariables}
|
||||
onSelect={this.handleQuickVariableSelect}
|
||||
popOverContainer={popOverContainer}
|
||||
simplifyMemberOprs
|
||||
/>
|
||||
</ul>
|
||||
);
|
||||
|
@ -484,6 +484,7 @@ export class TextareaFormulaControl extends React.Component<
|
||||
data={quickVariables}
|
||||
onSelect={this.handleQuickVariableSelect}
|
||||
popOverContainer={popOverContainer}
|
||||
simplifyMemberOprs
|
||||
/>
|
||||
</ul>
|
||||
);
|
||||
|
@ -302,6 +302,7 @@
|
||||
white-space: nowrap;
|
||||
|
||||
& > label {
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
@ -311,6 +312,10 @@
|
||||
min-width: #{px2rem(50px)};
|
||||
}
|
||||
|
||||
& > .icon {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.fa-ellipsis-h {
|
||||
margin-right: #{px2rem(5px)};
|
||||
&:hover {
|
||||
@ -319,6 +324,7 @@
|
||||
}
|
||||
|
||||
&-tag {
|
||||
cursor: auto;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
padding: 0 #{px2rem(8px)};
|
||||
|
@ -5,6 +5,7 @@ import GroupedSelection from '../GroupedSelection';
|
||||
import Tabs, {Tab} from '../Tabs';
|
||||
import TreeSelection from '../TreeSelection';
|
||||
import SearchBox from '../SearchBox';
|
||||
import {Icon} from '../icons';
|
||||
|
||||
import type {VariableItem} from './CodeEditor';
|
||||
import type {ItemRenderStates} from '../Selection';
|
||||
@ -42,29 +43,34 @@ const memberOpers = [
|
||||
'即当前列表中所有符合该成员条件的记录总数,需补充成员条件,例如:item.xxx === 1'
|
||||
},
|
||||
{
|
||||
label: '取该成员去重之后的总数',
|
||||
label: '去重计数:取该成员去重之后的总数',
|
||||
value: 'COUNT(UNIQ(${arr}, item.${member}))',
|
||||
description: '即对该成员记录进行去重,并统计总数'
|
||||
description: '即对该成员记录进行去重,并统计总数',
|
||||
simple: true
|
||||
},
|
||||
{
|
||||
label: '取该成员的总和',
|
||||
label: '求和:求当前列的所有值之和',
|
||||
value: 'SUM(ARRAYMAP(${arr}, item => item.${member}))',
|
||||
description: '即计算该成员记录的总和,需确认该成员记录均为数字类型'
|
||||
description: '即计算该成员记录的总和,需确认该成员记录均为数字类型',
|
||||
simple: true
|
||||
},
|
||||
{
|
||||
label: '取该成员的平均值',
|
||||
label: '平均值:求当前列的平均值',
|
||||
value: 'AVG(ARRAYMAP(${arr}, item => item.${member}))',
|
||||
description: '即计算该成员记录的平均值,需确认该成员记录均为数字类型'
|
||||
description: '即计算该成员记录的平均值,需确认该成员记录均为数字类型',
|
||||
simple: true
|
||||
},
|
||||
{
|
||||
label: '取该成员的最大值',
|
||||
label: '最大值:取当前列的最大值',
|
||||
value: 'MAX(ARRAYMAP(${arr}, item => item.${member}))',
|
||||
description: '即计算该成员记录中最大值,需确认该成员记录均为数字类型'
|
||||
description: '即计算该成员记录中最大值,需确认该成员记录均为数字类型',
|
||||
simple: true
|
||||
},
|
||||
{
|
||||
label: '取该成员的最小值',
|
||||
label: '最小值:取当前列的最小值',
|
||||
value: 'MIN(ARRAYMAP(${arr}, item => item.${member}))',
|
||||
description: '即计算该成员记录中最小值,需确认该成员记录均为数字类型'
|
||||
description: '即计算该成员记录中最小值,需确认该成员记录均为数字类型',
|
||||
simple: true
|
||||
}
|
||||
];
|
||||
|
||||
@ -80,6 +86,7 @@ export interface VariableListProps extends ThemeProps, SpinnerExtraProps {
|
||||
onSelect?: (item: VariableItem) => void;
|
||||
selfVariableName?: string;
|
||||
expandTree?: boolean;
|
||||
simplifyMemberOprs?: boolean;
|
||||
popOverContainer?: () => HTMLElement;
|
||||
}
|
||||
|
||||
@ -96,6 +103,7 @@ function VariableList(props: VariableListProps) {
|
||||
placeholderRender,
|
||||
selfVariableName,
|
||||
expandTree,
|
||||
simplifyMemberOprs,
|
||||
popOverContainer
|
||||
} = props;
|
||||
const [variables, setVariables] = React.useState<Array<VariableItem>>([]);
|
||||
@ -177,28 +185,30 @@ function VariableList(props: VariableListProps) {
|
||||
}
|
||||
popOverRender={({onClose}) => (
|
||||
<ul className={cx(`${classPrefix}-item-oper`)}>
|
||||
{memberOpers.map((item, i) => {
|
||||
return (
|
||||
<TooltipWrapper
|
||||
key={i}
|
||||
tooltip={item.description}
|
||||
tooltipTheme="dark"
|
||||
>
|
||||
<li
|
||||
{memberOpers
|
||||
.filter(item => !simplifyMemberOprs || item.simple)
|
||||
.map((item, i) => {
|
||||
return (
|
||||
<TooltipWrapper
|
||||
key={i}
|
||||
onClick={() =>
|
||||
handleMemberClick(
|
||||
{...item, isMember: true},
|
||||
option,
|
||||
onClose
|
||||
)
|
||||
}
|
||||
tooltip={item.description}
|
||||
tooltipTheme="dark"
|
||||
>
|
||||
<span>{item.label}</span>
|
||||
</li>
|
||||
</TooltipWrapper>
|
||||
);
|
||||
})}
|
||||
<li
|
||||
key={i}
|
||||
onClick={() =>
|
||||
handleMemberClick(
|
||||
{...item, isMember: true},
|
||||
option,
|
||||
onClose
|
||||
)
|
||||
}
|
||||
>
|
||||
<span>{item.label}</span>
|
||||
</li>
|
||||
</TooltipWrapper>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
)}
|
||||
>
|
||||
@ -207,7 +217,14 @@ function VariableList(props: VariableListProps) {
|
||||
tooltip={option.description ?? option.label}
|
||||
tooltipTheme="dark"
|
||||
>
|
||||
<label onClick={onClick}>{option.label}</label>
|
||||
<>
|
||||
<label onClick={onClick}>{option.label}</label>
|
||||
<Icon
|
||||
onClick={onClick}
|
||||
icon="ellipsis-v"
|
||||
className="icon"
|
||||
/>
|
||||
</>
|
||||
</TooltipWrapper>
|
||||
)}
|
||||
</PopOverContainer>
|
||||
|
Loading…
Reference in New Issue
Block a user