合并pre-release分支,解决一个文件冲突InputDateRange.tsx [amis-saas-6890]

Change-Id: I8432f63f419e383d2e7e646339c5047f4069c6d4
This commit is contained in:
jiatianqi 2022-11-09 14:34:21 +08:00
commit 0040c36815
13 changed files with 302 additions and 134 deletions

View File

@ -3,7 +3,10 @@
*/
import flatten from 'lodash/flatten';
import {getEventControlConfig, SUPPORT_STATIC_FORMITEM_CMPTS} from '../renderer/event-control/helper';
import {
getEventControlConfig,
SUPPORT_STATIC_FORMITEM_CMPTS
} from '../renderer/event-control/helper';
import {getSchemaTpl, isObject, tipedLabel} from 'amis-editor-core';
import type {BaseEventContext} from 'amis-editor-core';
import {SchemaObject} from 'amis/lib/Schema';
@ -340,12 +343,14 @@ export const formItemControl: (
name: 'descriptionClassName',
visibleOn: 'this.description'
}),
...!supportStatic ? [] : [
getSchemaTpl('className', {
label: '静态 CSS 类名',
name: 'staticClassName'
})
]
...(!supportStatic
? []
: [
getSchemaTpl('className', {
label: '静态 CSS 类名',
name: 'staticClassName'
})
])
],
panels?.style?.body,
panels?.style?.replace,
@ -471,10 +476,11 @@ export function remarkTpl(config: {
}
]
},
getSchemaTpl('icon', {
{
type: 'icon-select',
name: 'icon',
label: '图标'
}),
},
{
name: 'className',
label: 'CSS 类名',

View File

@ -8,8 +8,10 @@ import {
diff,
defaultValue,
getSchemaTpl,
CodeEditor as AmisCodeEditor
CodeEditor as AmisCodeEditor,
RendererPluginEvent
} from 'amis-editor-core';
import {getEventControlConfig} from '../renderer/event-control/helper';
const ChartConfigEditor = ({value, onChange}: any) => {
return (
@ -19,6 +21,54 @@ const ChartConfigEditor = ({value, onChange}: any) => {
);
};
const DEFAULT_EVENT_PARAMS = [
{
type: 'object',
properties: {
'event.data.componentType': {
type: 'string',
title: 'componentType'
},
'event.data.seriesType': {
type: 'string',
title: 'seriesType'
},
'event.data.seriesIndex': {
type: 'number',
title: 'seriesIndex'
},
'event.data.seriesName': {
type: 'string',
title: 'seriesName'
},
'event.data.name': {
type: 'string',
title: 'name'
},
'event.data.dataIndex': {
type: 'number',
title: 'dataIndex'
},
'event.data.data': {
type: 'object',
title: 'data'
},
'event.data.dataType': {
type: 'string',
title: 'dataType'
},
'event.data.value': {
type: 'number',
title: 'data'
},
'event.data.color': {
type: 'string',
title: 'color'
}
}
}
];
export class ChartPlugin extends BasePlugin {
// 关联渲染器名字
rendererName = 'chart';
@ -56,6 +106,42 @@ export class ChartPlugin extends BasePlugin {
...this.scaffold
};
// 事件定义
events: RendererPluginEvent[] = [
{
eventName: 'click',
eventLabel: '鼠标点击',
description: '鼠标点击时触发',
dataSchema: DEFAULT_EVENT_PARAMS
},
{
eventName: 'mouseover',
eventLabel: '鼠标悬停',
description: '鼠标悬停时触发',
dataSchema: DEFAULT_EVENT_PARAMS
},
{
eventName: 'legendselectchanged',
eventLabel: '切换图例选中状态',
description: '切换图例选中状态时触发',
dataSchema: [
{
type: 'object',
properties: {
'event.data.name': {
type: 'string',
title: 'name'
},
'event.data.selected': {
type: 'object',
title: 'selected'
}
}
}
]
}
];
// 动作定义
actions: RendererPluginAction[] = [
{
@ -68,6 +154,7 @@ export class ChartPlugin extends BasePlugin {
actionLabel: '更新数据',
description: '触发组件数据更新'
}
// 特性动作太多了,这里先不加了,可以通过写代码配置
];
panelTitle = '图表';
@ -184,6 +271,16 @@ export class ChartPlugin extends BasePlugin {
{
title: '其他',
body: [getSchemaTpl('name')]
},
{
title: '事件',
className: 'p-none',
body: [
getSchemaTpl('eventControl', {
name: 'onEvent',
...getEventControlConfig(this.manager, context)
})
]
}
])
];

View File

@ -6,15 +6,19 @@ import {ValidatorTag} from '../../validator';
import {getEventControlConfig} from '../../renderer/event-control/helper';
import {FormulaDateType} from '../../renderer/FormulaControl';
import {RendererPluginAction, RendererPluginEvent} from 'amis-editor-core';
import {getRendererByName} from 'amis-core';
const DateType: {
[key: string]: {
format: string;
placeholder: string;
ranges: string[];
sizeMutable?: boolean;
type?: string;
};
} = {
date: {
...getRendererByName('input-date-range'),
format: 'YYYY-MM-DD',
placeholder: '请选择日期范围',
ranges: [
@ -27,6 +31,7 @@ const DateType: {
]
},
datetime: {
...getRendererByName('input-datetime-range'),
format: 'YYYY-MM-DD HH:mm:ss',
placeholder: '请选择日期时间范围',
ranges: [
@ -39,21 +44,25 @@ const DateType: {
]
},
time: {
...getRendererByName('input-time-range'),
format: 'HH:mm',
placeholder: '请选择时间范围',
ranges: []
},
month: {
...getRendererByName('input-month-range'),
format: 'YYYY-MM',
placeholder: '请选择月份范围',
ranges: []
},
quarter: {
...getRendererByName('input-quarter-range'),
format: 'YYYY [Q]Q',
placeholder: '请选择季度范围',
ranges: ['thisquarter', 'prevquarter']
},
year: {
...getRendererByName('input-year-range'),
format: 'YYYY',
placeholder: '请选择年范围',
ranges: ['thisyear', 'lastYear']
@ -65,6 +74,10 @@ const dateTooltip =
const rangTooltip =
'支持例如: <code>3days、2weeks、1hour、2years</code> 等minute|hour|day|week|month|year|weekday|second|millisecond这种相对值用法';
const sizeImmutableComponents = Object.values(DateType)
.map(item => (item?.sizeMutable === false ? item.type : null))
.filter(a => a);
export class DateRangeControlPlugin extends BasePlugin {
// 关联渲染器名字
rendererName = 'input-date-range';
@ -209,7 +222,11 @@ export class DateRangeControlPlugin extends BasePlugin {
minDate: '',
maxDate: '',
value: '',
ranges: DateType[type]?.ranges
ranges: DateType[type]?.ranges,
// size immutable 组件去除 size 字段
size: sizeImmutableComponents.includes(value)
? undefined
: form.data?.size
});
}
}),
@ -315,14 +332,14 @@ export class DateRangeControlPlugin extends BasePlugin {
getSchemaTpl('dateShortCutControl', {
mode: 'normal',
normalDropDownOption: {
'yesterday': '昨天',
'thisweek': '这个周',
'prevweek': '上周',
'thismonth': '这个月',
'prevmonth': '上个月',
'thisquarter': '这个季度',
'prevquarter': '上个季度',
'thisyear': '今年'
yesterday: '昨天',
thisweek: '这个周',
prevweek: '上周',
thismonth: '这个月',
prevmonth: '上个月',
thisquarter: '这个季度',
prevquarter: '上个季度',
thisyear: '今年'
},
customDropDownOption: {
daysago: '最近n天',
@ -367,7 +384,17 @@ export class DateRangeControlPlugin extends BasePlugin {
body: getSchemaTpl(
'collapseGroup',
[
getSchemaTpl('style:formItem', renderer),
getSchemaTpl('style:formItem', {
renderer: {...renderer, sizeMutable: false},
schema: [
// 需要作为一个字符串表达式传入,因为切换 type 后 panelBodyCreator 不会重新执行
getSchemaTpl('formItemSize', {
hiddenOn: `["${sizeImmutableComponents.join(
'","'
)}"].includes(this.type)`
})
]
}),
getSchemaTpl('style:classNames', [
getSchemaTpl('className', {
label: '描述',

View File

@ -261,7 +261,7 @@ export class NumberControlPlugin extends BasePlugin {
label: '快捷编辑',
name: 'displayMode',
type: 'select',
value: 'base',
pipeIn: defaultValue('base'),
options: [
{
label: '单侧按钮',

View File

@ -112,28 +112,18 @@ export class RateControlPlugin extends BasePlugin {
valueType: 'number', // 期望数值类型
visibleOn: '!data.multiple'
}),
// 评分组件没有 min、max 属性,有 count 属性
getSchemaTpl('valueFormula', {
name: 'min',
name: 'count',
rendererSchema: {
...context?.schema,
type: 'input-number'
type: 'input-number',
max: 10,
min: 1,
step: 1,
precision: 0
},
needDeleteProps: ['min'], // 避免自我限制
label: tipedLabel(
'最小值',
'请输入数字或使用 <code>\\${xxx}</code> 来获取变量,否则该配置不生效'
),
valueType: 'number'
}),
getSchemaTpl('valueFormula', {
name: 'max',
rendererSchema: {
...context?.schema,
type: 'input-number'
},
needDeleteProps: ['max'], // 避免自我限制
needDeleteProps: ['count'], // 避免自我限制
label: tipedLabel(
'最大值',
'请输入数字或使用 <code>\\${xxx}</code> 来获取变量,否则该配置不生效'

View File

@ -51,35 +51,16 @@ export class LinkPlugin extends BasePlugin {
name: 'blank',
label: '在新窗口打开'
}),
{
label: '图标位置',
type: 'button-group-select',
name: 'position',
pipeIn: defaultValue('rightIcon'),
size: 'sm',
value: 'rightIcon',
options: [
{
label: '左侧',
value: 'icon'
},
{
label: '右侧',
value: 'rightIcon'
}
]
},
getSchemaTpl('iconLink', {
name: 'icon',
visibleOn: 'this.position == "icon"'
label: '左侧图标'
}),
getSchemaTpl('iconLink', {
name: 'rightIcon',
visibleOn: 'this.position == "rightIcon"'
}),
label: '右侧图标'
})
]
},
getSchemaTpl('status', {

View File

@ -210,6 +210,7 @@ export class PagePlugin extends BasePlugin {
}),
getSchemaTpl('apiControl', {
name: 'initApi',
mode: 'row',
labelClassName: 'none',
label: tipedLabel(
'初始化接口',

View File

@ -1,6 +1,5 @@
import React from 'react';
import merge from 'lodash/merge';
import isEqual from 'lodash/isEqual';
import mergeWith from 'lodash/mergeWith';
import cloneDeep from 'lodash/cloneDeep';
import cx from 'classnames';
import {FormItem, Icon} from 'amis';
@ -324,7 +323,23 @@ export default class APIControl extends React.Component<
}
if (typeof value !== 'string' || typeof values !== 'string') {
api = merge({}, normalizeApi(values));
api = mergeWith(
{},
normalizeApi(value),
normalizeApi(values),
(value, srcValue, key) => {
// 这三个支持删除单个key的属性需用新值完全替换
// 否则删除无效
if (['data', 'responseData', 'headers'].includes(key)) {
return srcValue;
}
}
);
['data', 'responseData', 'headers'].forEach((item: keyof Api) => {
if (api[item] == null) {
delete api[item];
}
});
}
onChange?.(api);
}

View File

@ -1,5 +1,5 @@
import React from 'react';
import merge from 'lodash/merge';
import mergeWith from 'lodash/mergeWith';
import cloneDeep from 'lodash/cloneDeep';
import cx from 'classnames';
import {FormItem, InputBox} from 'amis';
@ -195,7 +195,23 @@ export default class APIControl extends React.Component<
}
if (typeof value !== 'string' || typeof values !== 'string') {
api = merge({}, normalizeApi(value), normalizeApi(values));
api = mergeWith(
{},
normalizeApi(value),
normalizeApi(values),
(value, srcValue, key) => {
// 这三个支持删除单个key的属性需用新值完全替换
// 否则删除无效
if (['data', 'responseData', 'headers'].includes(key)) {
return srcValue;
}
}
);
['data', 'responseData', 'headers'].forEach((item: keyof Api) => {
if (api[item] == null) {
delete api[item];
}
});
}
onChange?.(api);

View File

@ -44,31 +44,31 @@ interface DateShortCutControlState {
}
interface InputOption {
type: 'middle' | 'suffix',
prefix?: string,
suffix: string
type: 'middle' | 'suffix';
prefix?: string;
suffix: string;
}
const ShortCutItemWrap = (
props: {
index: number,
children: React.ReactNode,
handleDelete: (index: number, e: React.SyntheticEvent<any>) => void
}) => {
const ShortCutItemWrap = (props: {
index: number;
children: React.ReactNode;
handleDelete: (index: number, e: React.SyntheticEvent<any>) => void;
}) => {
return (
<>
<a className={klass + 'Item-dragBar'}><Icon icon='drag-bar' className='icon' /></a>
<span className={klass + 'Item-content'}>
{props.children}
</span>
<a className={klass + 'Item-dragBar'}>
<Icon icon="drag-bar" className="icon" />
</a>
<span className={klass + 'Item-content'}>{props.children}</span>
<span
className={klass + 'Item-close'}
onClick={(e) => props.handleDelete(props.index, e)}>
<Icon icon='status-close' className='icon' />
onClick={e => props.handleDelete(props.index, e)}
>
<Icon icon="status-close" className="icon" />
</span>
</>
);
}
};
const klass = 'ae-DateShortCutControl';
@ -80,7 +80,7 @@ export class DateShortCutControl extends React.PureComponent<
drag?: HTMLElement | null;
target: HTMLElement | null;
normalDropDownOptionArr: Array<Option>;
customDropDownOptionArr: Array<Option>
customDropDownOptionArr: Array<Option>;
static defaultProps: Partial<DateShortCutControlProps> = {
label: '快捷键'
@ -89,14 +89,18 @@ export class DateShortCutControl extends React.PureComponent<
constructor(props: DateShortCutControlProps) {
super(props);
const {normalDropDownOption, customDropDownOption, data} = props;
this.normalDropDownOptionArr = Object.keys(normalDropDownOption).map(key => ({
label: normalDropDownOption[key],
value: key
}));
this.customDropDownOptionArr = Object.keys(customDropDownOption).map(key => ({
label: customDropDownOption[key],
value: key
}));
this.normalDropDownOptionArr = Object.keys(normalDropDownOption).map(
key => ({
label: normalDropDownOption[key],
value: key
})
);
this.customDropDownOptionArr = Object.keys(customDropDownOption).map(
key => ({
label: customDropDownOption[key],
value: key
})
);
const defaultRanges = [
'yesterday',
'7daysago',
@ -106,21 +110,23 @@ export class DateShortCutControl extends React.PureComponent<
'prevquarter'
];
this.state = {
options: (data?.ranges ?? defaultRanges).map((item: string, index: number) => {
const arr = item.match(/^(\d+)[a-zA-Z]+/);
if (arr) {
return {
value: arr[1],
type: RangeType.Custom,
inputType: item.match(/[a-zA-Z]+/)?.[0]
options: (data?.ranges ?? defaultRanges).map(
(item: string, index: number) => {
const arr = item.match(/^(\d+)[a-zA-Z]+/);
if (arr) {
return {
value: arr[1],
type: RangeType.Custom,
inputType: item.match(/[a-zA-Z]+/)?.[0]
};
}
}
return {
return {
label: normalDropDownOption[item],
value: item,
type: RangeType.Normal,
type: RangeType.Normal
};
}
})
)
};
}
@ -205,15 +211,13 @@ export class DateShortCutControl extends React.PureComponent<
<div className={klass + '-wrapper'}>
{options && options.length ? (
<ul className={klass + '-content'} ref={this.dragRef}>
{options.map(
(option, index) =>
<li className={klass + 'Item'} key={index}>
{option.type === RangeType.Normal
? this.renderNormalOption(option, index)
: this.renderCustomOption(option, index)}
</li>
)
}
{options.map((option, index) => (
<li className={klass + 'Item'} key={index}>
{option.type === RangeType.Normal
? this.renderNormalOption(option, index)
: this.renderCustomOption(option, index)}
</li>
))}
</ul>
) : (
<div className={klass + '-content ' + klass + '-empty'}></div>
@ -229,7 +233,8 @@ export class DateShortCutControl extends React.PureComponent<
return (
<ShortCutItemWrap index={index} handleDelete={this.handleDelete}>
<span>{option.label}</span>
</ShortCutItemWrap>);
</ShortCutItemWrap>
);
}
/**
@ -248,7 +253,7 @@ export class DateShortCutControl extends React.PureComponent<
placeholder: 'n',
value: option?.value,
onChange: (value: string) => this.handleCustomItemChange(value, index)
})
});
}
return render('inner', {
type: 'input-text',
@ -257,8 +262,8 @@ export class DateShortCutControl extends React.PureComponent<
suffix: option.suffix,
value: option?.value,
onChange: (value: string) => this.handleCustomItemChange(value, index)
})
}
});
};
const dateMap: {[key: string]: InputOption} = {
daysago: {prefix: '最近', suffix: '天', type: 'middle'},
@ -271,8 +276,8 @@ export class DateShortCutControl extends React.PureComponent<
quarterslater: {suffix: '季度以内', type: 'suffix'},
yearsago: {prefix: '最近', suffix: '年', type: 'middle'},
yearslater: {suffix: '年以内', type: 'suffix'}
}
};
return (
<ShortCutItemWrap index={index} handleDelete={this.handleDelete}>
{option.inputType
@ -359,10 +364,12 @@ export class DateShortCutControl extends React.PureComponent<
label: '常用跨度',
closeOnClick: true,
closeOnOutside: true,
level: 'enhance',
buttons: this.normalDropDownOptionArr.map((item: any) => ({
...item,
type: 'button',
onAction: (e: React.MouseEvent, action: any) => this.addItem(item, RangeType.Normal)
onAction: (e: React.MouseEvent, action: any) =>
this.addItem(item, RangeType.Normal)
}))
},
{
@ -381,7 +388,8 @@ export class DateShortCutControl extends React.PureComponent<
buttons: this.customDropDownOptionArr.map((item: any) => ({
...item,
type: 'button',
onAction: (e: React.MouseEvent, action: any) => this.addItem(item, RangeType.Custom)
onAction: (e: React.MouseEvent, action: any) =>
this.addItem(item, RangeType.Custom)
}))
},
{

View File

@ -356,7 +356,7 @@ export default class SwitchMore extends React.Component<
return {
type: 'input-sub-form',
btnLabel: '',
className: 'inline-block m-0 h-6',
className: 'inline-block m-0 h-6 bg-white ',
itemClassName: 'bg-white hover:bg-white m-0 p-0',
icon: 'fa fa-cog',
form: {

View File

@ -361,12 +361,39 @@ const Background: React.FC<BackgroundProps> = props => {
setTabIndex(index);
}
function handleChange(key: string, keyValue: string) {
function handleChange(key: string, keyValue: string | number) {
const {value, onChange} = props;
const result = {
...value,
[key]: keyValue
};
let result = {};
if (key === 'backgroundColor') {
result = {
...omit(value, [
'backgroundImage',
'backgroundPosition',
'backgroundSize',
'backgroundRepeat',
'angle'
]),
[key]: keyValue
};
} else if (key === 'angle') {
keyValue = keyValue || 0;
const linearGradient = value?.backgroundImage;
let backgroundImage = linearGradient?.replace(
/(\d{1,})?deg/,
`${keyValue}deg`
);
result = {
...value,
backgroundImage
};
} else {
result = {
...value,
[key]: keyValue
};
}
onChange(result);
}

View File

@ -124,7 +124,7 @@ setSchemaTpl('formItemSize', {
name: 'size',
label: '控件宽度',
type: 'select',
pipeIn: defaultValue(''),
pipeIn: defaultValue('full'),
// mode: 'inline',
// className: 'w-full',
options: [
@ -148,12 +148,8 @@ setSchemaTpl('formItemSize', {
value: 'lg'
},
{
label: '占满',
label: '默认(占满',
value: 'full'
},
{
label: '默认',
value: ''
}
]
});
@ -1138,12 +1134,16 @@ setSchemaTpl('app-page-args', {
setSchemaTpl(
'iconLink',
(schema: {name: 'icon' | 'rightIcon'; visibleOn: boolean}) => {
const {name, visibleOn} = schema;
(schema: {
name: 'icon' | 'rightIcon';
visibleOn: boolean;
label?: string;
}) => {
const {name, visibleOn, label} = schema;
return getSchemaTpl('icon', {
name: name,
visibleOn,
label: '图标',
label: label ?? '图标',
placeholder: '点击选择图标',
clearable: true,
description: ''