amis-saas-6892 [Feature] fx公式函数支持日期类快捷键功能

Change-Id: I7ec472578ed7fdf4c66bb963caa482a7f98ed7b8
This commit is contained in:
jiatianqi 2022-09-22 19:09:46 +08:00
parent 035d1e4b0e
commit 3a50a31cea
4 changed files with 131 additions and 67 deletions

View File

@ -4,6 +4,7 @@ import {BasePlugin, BaseEventContext, tipedLabel} from 'amis-editor-core';
import {ValidatorTag} from '../../validator'; import {ValidatorTag} from '../../validator';
import {getEventControlConfig} from '../../renderer/event-control/helper'; import {getEventControlConfig} from '../../renderer/event-control/helper';
import {FormulaDateType} from '../../renderer/FormulaControl';
import {RendererPluginAction, RendererPluginEvent} from 'amis-editor-core'; import {RendererPluginAction, RendererPluginEvent} from 'amis-editor-core';
const formatX = [ const formatX = [
@ -135,8 +136,8 @@ const DateType: {
} }
}; };
const tipedLabelText = const dateTooltip =
'支持 <code>now、+1day、-2weeks、+1hours、+2years</code>这种相对值用法,同时支持变量如<code>\\${start_date}</code>'; '支持例如: <code>now、+3days、-2weeks、+1hour、+2years</code> 等minute|min|hour|day|week|month|year|weekday|second|millisecond这种相对值用法';
export class DateControlPlugin extends BasePlugin { export class DateControlPlugin extends BasePlugin {
// 关联渲染器名字 // 关联渲染器名字
@ -312,28 +313,31 @@ export class DateControlPlugin extends BasePlugin {
}), }),
getSchemaTpl('valueFormula', { getSchemaTpl('valueFormula', {
rendererSchema: context?.schema, rendererSchema: context?.schema,
label: tipedLabel( header: '表达式或相对值',
'默认值', DateTimeType: FormulaDateType.IsDate,
'支持 <code>now、+1day、-2weeks、+1hours、+2years</code>等这种相对值用法' label: tipedLabel('默认值', dateTooltip)
)
}), }),
getSchemaTpl('valueFormula', { getSchemaTpl('valueFormula', {
name: 'minDate', name: 'minDate',
header: '表达式或相对值',
DateTimeType: FormulaDateType.IsDate,
rendererSchema: { rendererSchema: {
...context?.schema, ...context?.schema,
value: context?.schema.minDate value: context?.schema.minDate
}, },
needDeleteProps: ['minDate'], // 避免自我限制 needDeleteProps: ['minDate'], // 避免自我限制
label: tipedLabel('最小值', tipedLabelText) label: tipedLabel('最小值', dateTooltip)
}), }),
getSchemaTpl('valueFormula', { getSchemaTpl('valueFormula', {
name: 'maxDate', name: 'maxDate',
header: '表达式或相对值',
DateTimeType: FormulaDateType.IsDate,
rendererSchema: { rendererSchema: {
...context?.schema, ...context?.schema,
value: context?.schema.maxDate value: context?.schema.maxDate
}, },
needDeleteProps: ['maxDate'], // 避免自我限制 needDeleteProps: ['maxDate'], // 避免自我限制
label: tipedLabel('最大值', tipedLabelText) label: tipedLabel('最大值', dateTooltip)
}), }),
getSchemaTpl('placeholder', { getSchemaTpl('placeholder', {
pipeIn: defaultValue('请选择日期') pipeIn: defaultValue('请选择日期')

View File

@ -4,6 +4,7 @@ import {BasePlugin, BaseEventContext} from 'amis-editor-core';
import {ValidatorTag} from '../../validator'; import {ValidatorTag} from '../../validator';
import {getEventControlConfig} from '../../renderer/event-control/helper'; import {getEventControlConfig} from '../../renderer/event-control/helper';
import {FormulaDateType} from '../../renderer/FormulaControl';
import {RendererPluginAction, RendererPluginEvent} from 'amis-editor-core'; import {RendererPluginAction, RendererPluginEvent} from 'amis-editor-core';
const DateType: { const DateType: {
@ -59,8 +60,10 @@ const DateType: {
} }
}; };
const tipedLabelText = const dateTooltip =
'支持 <code>now、+1day、-2weeks、+1hours、+2years</code>这种相对值用法,同时支持变量如<code>\\${start_date}</code>'; '支持例如: <code>now、+3days、-2weeks、+1hour、+2years</code> 等minute|hour|day|week|month|year|weekday|second|millisecond这种相对值用法';
const rangTooltip =
'支持例如: <code>3days、2weeks、1hour、2years</code> 等minute|hour|day|week|month|year|weekday|second|millisecond这种相对值用法';
export class DateRangeControlPlugin extends BasePlugin { export class DateRangeControlPlugin extends BasePlugin {
// 关联渲染器名字 // 关联渲染器名字
@ -247,63 +250,65 @@ export class DateRangeControlPlugin extends BasePlugin {
}), }),
getSchemaTpl('valueFormula', { getSchemaTpl('valueFormula', {
/* : amis
rendererSchema: {
...context?.schema,
size: 'full', // 备注目前样式还有问题需要在amis端进行优化
mode: "inline"
},
mode: 'vertical',
*/
rendererSchema: { rendererSchema: {
type: 'input-date' ...context?.schema,
size: 'full',
mode: 'inline'
}, },
label: tipedLabel( mode: 'vertical',
'默认值', header: '表达式或相对值',
'支持 <code>now、+1day、-2weeks、+1hours、+2years</code>等这种相对值用法' DateTimeType: FormulaDateType.IsDate,
) label: tipedLabel('默认值', dateTooltip)
}), }),
getSchemaTpl('valueFormula', { getSchemaTpl('valueFormula', {
name: 'minDate', name: 'minDate',
header: '表达式或相对值',
DateTimeType: FormulaDateType.IsDate,
rendererSchema: { rendererSchema: {
...context?.schema, ...context?.schema,
value: context?.schema.minDate, value: context?.schema.minDate,
type: 'input-date' type: 'input-date'
}, },
needDeleteProps: ['minDate'], // 避免自我限制 needDeleteProps: ['minDate'], // 避免自我限制
label: tipedLabel('最小值', tipedLabelText) label: tipedLabel('最小值', dateTooltip)
}), }),
getSchemaTpl('valueFormula', { getSchemaTpl('valueFormula', {
name: 'maxDate', name: 'maxDate',
header: '表达式或相对值',
DateTimeType: FormulaDateType.IsDate,
rendererSchema: { rendererSchema: {
...context?.schema, ...context?.schema,
value: context?.schema.maxDate, value: context?.schema.maxDate,
type: 'input-date' type: 'input-date'
}, },
needDeleteProps: ['maxDate'], // 避免自我限制 needDeleteProps: ['maxDate'], // 避免自我限制
label: tipedLabel('最大值', tipedLabelText) label: tipedLabel('最大值', dateTooltip)
}), }),
getSchemaTpl('valueFormula', { getSchemaTpl('valueFormula', {
name: 'minDuration', name: 'minDuration',
header: '表达式或相对值',
DateTimeType: FormulaDateType.IsRange,
rendererSchema: { rendererSchema: {
...context?.schema, ...context?.schema,
value: context?.schema.minDuration, value: context?.schema.minDuration,
type: 'input-text' type: 'input-text'
}, },
needDeleteProps: ['minDuration'], // 避免自我限制 needDeleteProps: ['minDuration'], // 避免自我限制
label: tipedLabel('最小跨度', '例如 2days') label: tipedLabel('最小跨度', rangTooltip)
}), }),
getSchemaTpl('valueFormula', { getSchemaTpl('valueFormula', {
name: 'maxDuration', name: 'maxDuration',
header: '表达式或相对值',
DateTimeType: FormulaDateType.IsRange,
rendererSchema: { rendererSchema: {
...context?.schema, ...context?.schema,
value: context?.schema.maxDuration, value: context?.schema.maxDuration,
type: 'input-text' type: 'input-text'
}, },
needDeleteProps: ['maxDuration'], // 避免自我限制 needDeleteProps: ['maxDuration'], // 避免自我限制
label: tipedLabel('最大跨度', '例如 1year') label: tipedLabel('最大跨度', rangTooltip)
}), }),
getSchemaTpl('dateShortCutControl', { getSchemaTpl('dateShortCutControl', {
mode: 'normal', mode: 'normal',

View File

@ -15,7 +15,7 @@ import omit from 'lodash/omit';
import cx from 'classnames'; import cx from 'classnames';
import {FormItem, Button, InputBox, Icon, ResultBox} from 'amis'; import {FormItem, Button, InputBox, Icon, ResultBox} from 'amis';
import {FormulaExec, isExpression} from 'amis'; import {FormulaExec, isExpression} from 'amis';
import {PickerContainer} from 'amis'; import {PickerContainer, relativeValueRe} from 'amis';
import {FormulaEditor} from 'amis-ui/lib/components/formula/Editor'; import {FormulaEditor} from 'amis-ui/lib/components/formula/Editor';
import {autobind} from 'amis-editor-core'; import {autobind} from 'amis-editor-core';
@ -27,6 +27,13 @@ import type {
import {dataMapping, FormControlProps} from 'amis-core'; import {dataMapping, 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';
export enum FormulaDateType {
NotDate, // 不是时间类
IsDate, // 日期时间类
IsRange // 日期时间范围类
}
export interface FormulaControlProps extends FormControlProps { export interface FormulaControlProps extends FormControlProps {
manager?: EditorManager; manager?: EditorManager;
@ -95,6 +102,14 @@ export interface FormulaControlProps extends FormControlProps {
* 使Form数据 * 使Form数据
*/ */
useExternalFormData?: boolean; useExternalFormData?: boolean;
/**
* 使formulaControl
* 使 now+1day-2weeks+1hours+2years等这种相对值写法 ${}
* 使 1day2weeks1hours2years等这种相对值写法 ${}
* FormulaDateType.NotDate
*/
DateTimeType?: FormulaDateType;
} }
interface FormulaControlState { interface FormulaControlState {
@ -109,7 +124,8 @@ export default class FormulaControl extends React.Component<
FormulaControlState FormulaControlState
> { > {
static defaultProps: Partial<FormulaControlProps> = { static defaultProps: Partial<FormulaControlProps> = {
simple: false simple: false,
DateTimeType: FormulaDateType.NotDate
}; };
isUnmount: boolean; isUnmount: boolean;
@ -261,6 +277,28 @@ export default class FormulaControl extends React.Component<
} }
return []; return [];
} }
// 日期类组件 & 是否存在快捷键判断
@autobind
hasDateShortcutkey(str: string): boolean {
const {DateTimeType} = this.props;
if (DateTimeType === FormulaDateType.IsDate) {
return (
/^(\+|-)(\d+)(minute|min|hour|day|week|month|year|weekday|second|millisecond)s?$/i.test(
str
) || /^(now|today)$/.test(str)
);
} else if (DateTimeType === FormulaDateType.IsRange) {
return /^((?:\-|\+)?(?:\d*\.)?\d+)(minute|min|hour|day|week|month|quarter|year|weekday|second|millisecond)s?$/i.test(
str
);
}
// 非日期类组件使用也直接false
// if (DateTimeType === FormulaDateType.NotDate) {
// return false;
// }
return false;
}
@autobind @autobind
transExpr(str: string) { transExpr(str: string) {
@ -282,7 +320,7 @@ export default class FormulaControl extends React.Component<
handleConfirm(value: any) { handleConfirm(value: any) {
const val = !value const val = !value
? undefined ? undefined
: isExpression(value) : isExpression(value) || this.hasDateShortcutkey(value)
? value ? value
: `\${${value}}`; : `\${${value}}`;
this.props?.onChange?.(val); this.props?.onChange?.(val);
@ -421,7 +459,6 @@ export default class FormulaControl extends React.Component<
...rest ...rest
} = this.props; } = this.props;
const labelText = typeof label === 'string' ? label : '';
// 自身字段 // 自身字段
const selfName = this.props?.data?.name; const selfName = this.props?.data?.name;
@ -445,6 +482,13 @@ export default class FormulaControl extends React.Component<
? FormulaEditor.highlightValue(value, this.state.variables) ? FormulaEditor.highlightValue(value, this.state.variables)
: value; : value;
// 公式表达式弹窗内容过滤
const filterValue = isExpression(value)
? this.transExpr(value)
: this.hasDateShortcutkey(value)
? value
: undefined;
return ( return (
<div <div
className={cx( className={cx(
@ -453,39 +497,45 @@ export default class FormulaControl extends React.Component<
className className
)} )}
> >
{/* 非简单模式 & 非表达式 & 无自定义渲染 */} {/* 非简单模式 & 非表达式 & 非日期快捷 & 无自定义渲染 */}
{!simple && !isExpr && !rendererSchema && ( {!simple &&
<InputBox !isExpr &&
className="ae-editor-FormulaControl-input" !this.hasDateShortcutkey(value) &&
value={value} !rendererSchema && (
clearable={true} <InputBox
placeholder={placeholder} className="ae-editor-FormulaControl-input"
onChange={this.handleSimpleInputChange} value={value}
/> clearable={true}
)} placeholder={placeholder}
{/* 非简单模式 & 非表达式 & 自定义渲染 */} onChange={this.handleSimpleInputChange}
{!simple && !isExpr && rendererSchema && ( />
<div )}
className={cx( {/* 非简单模式 & 非表达式 & 非日期快捷 & 自定义渲染 */}
'ae-editor-FormulaControl-custom-renderer', {!simple &&
rendererWrapper ? 'border-wrapper' : '' !isExpr &&
)} !this.hasDateShortcutkey(value) &&
> rendererSchema && (
{render('inner', this.filterCustomRendererProps(rendererSchema), { <div
inputOnly: true, className={cx(
value: value, 'ae-editor-FormulaControl-custom-renderer',
data: useExternalFormData rendererWrapper ? 'border-wrapper' : ''
? { )}
...this.props.data >
} {render('inner', this.filterCustomRendererProps(rendererSchema), {
: {}, inputOnly: true,
onChange: this.handleSimpleInputChange, value: value,
manager: manager data: useExternalFormData
})} ? {
</div> ...this.props.data
)} }
{/* 非简单模式 & 表达式 */} : {},
{!simple && isExpr && ( onChange: this.handleSimpleInputChange,
manager: manager
})}
</div>
)}
{/* 非简单模式 &(表达式 或 日期快捷)*/}
{!simple && (isExpr || this.hasDateShortcutkey(value)) && (
<ResultBox <ResultBox
className={cx( className={cx(
'ae-editor-FormulaControl-ResultBox', 'ae-editor-FormulaControl-ResultBox',
@ -518,7 +568,7 @@ export default class FormulaControl extends React.Component<
variableMode={rest.variableMode ?? this.state.variableMode} variableMode={rest.variableMode ?? this.state.variableMode}
variables={this.state.variables} variables={this.state.variables}
header={header || '新表达式语法'} header={header || '新表达式语法'}
value={isExpression(value) ? this.transExpr(value) : undefined} value={filterValue}
onChange={onChange} onChange={onChange}
selfVariableName={selfName} selfVariableName={selfName}
/> />

View File

@ -10,6 +10,7 @@ import {remarkTpl} from '../component/BaseControl';
import {SchemaObject} from 'amis/lib/Schema'; import {SchemaObject} from 'amis/lib/Schema';
import flatten from 'lodash/flatten'; import flatten from 'lodash/flatten';
import {InputComponentName} from '../component/InputComponentName'; import {InputComponentName} from '../component/InputComponentName';
import {FormulaDateType} from '../renderer/FormulaControl';
/** /**
* @deprecated switch * @deprecated switch
@ -355,12 +356,14 @@ setSchemaTpl(
mode?: string; // 自定义展示默认值,上下展示: vertical, 左右展示: horizontal mode?: string; // 自定义展示默认值,上下展示: vertical, 左右展示: horizontal
label?: string; // 表单项 label label?: string; // 表单项 label
name?: string; // 表单项 name name?: string; // 表单项 name
header?: string; // 表达式弹窗标题
rendererSchema?: any; rendererSchema?: any;
rendererWrapper?: boolean; // 自定义渲染器 是否需要浅色边框包裹 rendererWrapper?: boolean; // 自定义渲染器 是否需要浅色边框包裹
needDeleteValue?: boolean; // 是否需要剔除默认值 needDeleteValue?: boolean; // 是否需要剔除默认值
useSelectMode?: boolean; // 是否使用Select选择设置模式需要确保 rendererSchema.options 不为 undefined useSelectMode?: boolean; // 是否使用Select选择设置模式需要确保 rendererSchema.options 不为 undefined
valueType?: string; // 用于设置期望数值类型 valueType?: string; // 用于设置期望数值类型
visibleOn?: string; // 用于控制显示的表达式 visibleOn?: string; // 用于控制显示的表达式
DateTimeType?: FormulaDateType; // 日期类组件要支持 表达式 & 相对值
}) => { }) => {
let curRendererSchema = config?.rendererSchema; let curRendererSchema = config?.rendererSchema;
if ( if (
@ -389,7 +392,8 @@ setSchemaTpl(
rendererWrapper: config?.rendererWrapper, rendererWrapper: config?.rendererWrapper,
needDeleteValue: config?.needDeleteValue, needDeleteValue: config?.needDeleteValue,
valueType: config?.valueType, valueType: config?.valueType,
header: '表达式' header: config.header ?? '表达式',
DateTimeType: config.DateTimeType ?? FormulaDateType.NotDate
} }
] ]
}; };
@ -404,7 +408,8 @@ setSchemaTpl(
needDeleteValue: config?.needDeleteValue, needDeleteValue: config?.needDeleteValue,
valueType: config?.valueType, valueType: config?.valueType,
visibleOn: config?.visibleOn, visibleOn: config?.visibleOn,
header: '表达式' header: config?.header ?? '表达式',
DateTimeType: config?.DateTimeType ?? FormulaDateType.NotDate
}; };
} }
} }