mirror of
https://gitee.com/baidu/amis.git
synced 2024-11-30 10:59:42 +08:00
merge feat-optimize-4
Change-Id: I8974063a944df31cfcd401f416b69859fa53c04d
This commit is contained in:
parent
29bd6b5e91
commit
ec4170017f
@ -4,9 +4,12 @@
|
||||
|
||||
import flatten from 'lodash/flatten';
|
||||
import {getEventControlConfig} from '../util';
|
||||
import {getSchemaTpl, isObject} from 'amis-editor-core';
|
||||
import type {BaseEventContext} from 'amis-editor-core';
|
||||
import {SchemaObject} from 'amis/lib/Schema';
|
||||
import {
|
||||
getSchemaTpl,
|
||||
isObject,
|
||||
BaseEventContext,
|
||||
tipedLabel
|
||||
} from 'amis-editor-core';
|
||||
|
||||
// 默认动作
|
||||
export const BUTTON_DEFAULT_ACTION = {
|
||||
@ -370,25 +373,6 @@ export const formItemControl: (
|
||||
];
|
||||
};
|
||||
|
||||
export function tipedLabel(
|
||||
body: string | Array<SchemaObject>,
|
||||
tip: string,
|
||||
style?: React.CSSProperties
|
||||
) {
|
||||
return {
|
||||
type: 'tooltip-wrapper',
|
||||
tooltip: tip,
|
||||
tooltipTheme: 'dark',
|
||||
placement: 'top',
|
||||
tooltipStyle: {
|
||||
fontSize: '12px',
|
||||
...(style || {})
|
||||
},
|
||||
className: 'ae-formItemControl-label-tip',
|
||||
body
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 信息提示组件模版
|
||||
*/
|
||||
@ -400,7 +384,7 @@ export function remarkTpl(config: {
|
||||
return {
|
||||
type: 'ae-switch-more',
|
||||
formType: 'dialog',
|
||||
className:'ae-switch-more-flex',
|
||||
className: 'ae-switch-more-flex',
|
||||
label: config.labelRemark
|
||||
? tipedLabel(config.label, config.labelRemark)
|
||||
: config.label,
|
||||
|
@ -7,7 +7,7 @@ interface InputComponentNameProps extends RendererProps {
|
||||
}
|
||||
|
||||
export function InputComponentName(props: InputComponentNameProps) {
|
||||
const {value, onChange, render, name, node} = props;
|
||||
const {value, onChange, render, name, node, placeholder} = props;
|
||||
const [options, setOptions] = useState<Array<any>>([]);
|
||||
|
||||
useEffect(() => {
|
||||
@ -37,7 +37,8 @@ export function InputComponentName(props: InputComponentNameProps) {
|
||||
'inner',
|
||||
{
|
||||
type: 'input-text',
|
||||
name
|
||||
name,
|
||||
placeholder
|
||||
},
|
||||
{
|
||||
value,
|
||||
|
@ -74,6 +74,7 @@ import './plugin/ButtonGroup';
|
||||
import './plugin/ButtonToolbar';
|
||||
import './plugin/Breadcrumb';
|
||||
import './plugin/Card';
|
||||
import './plugin/Card2';
|
||||
import './plugin/Cards';
|
||||
import './plugin/Carousel';
|
||||
import './plugin/Chart';
|
||||
@ -119,6 +120,8 @@ import './plugin/Steps';
|
||||
import './plugin/Sparkline';
|
||||
import './plugin/Submit';
|
||||
import './plugin/Table';
|
||||
import './plugin/Table-v2';
|
||||
import './plugin/TableCell-v2';
|
||||
import './plugin/Tabs';
|
||||
import './plugin/Tasks';
|
||||
import './plugin/Time';
|
||||
@ -131,6 +134,8 @@ import './plugin/TooltipWrapper';
|
||||
import './plugin/TableView';
|
||||
import './plugin/CodeView';
|
||||
import './plugin/WebComponent';
|
||||
import './plugin/CRUD2';
|
||||
import './plugin/ColumnToggler';
|
||||
|
||||
import {GridPlugin} from './plugin/Grid';
|
||||
|
||||
|
@ -78,7 +78,7 @@ export class AlertPlugin extends BasePlugin {
|
||||
name: 'showCloseButton'
|
||||
}),
|
||||
{
|
||||
type: 'ae-Switch-More',
|
||||
type: 'ae-switch-more',
|
||||
mode: 'normal',
|
||||
name: 'showIcon',
|
||||
label: '图标',
|
||||
|
@ -4,7 +4,7 @@
|
||||
import {registerEditorPlugin} from 'amis-editor-core';
|
||||
import {BaseEventContext, BasePlugin} from 'amis-editor-core';
|
||||
import {getSchemaTpl, defaultValue} from 'amis-editor-core';
|
||||
import {tipedLabel} from '../component/BaseControl';
|
||||
import {tipedLabel} from 'amis-editor-core';
|
||||
|
||||
const DefaultSize = 40;
|
||||
const DefaultBorderRadius = 20;
|
||||
@ -173,7 +173,7 @@ export class AvatarPlugin extends BasePlugin {
|
||||
visibleOn: 'data.showtype === "text"'
|
||||
}
|
||||
]
|
||||
},
|
||||
}
|
||||
// TODO 临时关闭,目前角标功能还没完善,待完善后再开启
|
||||
// getSchemaTpl('badge')
|
||||
]
|
||||
|
@ -4,10 +4,11 @@ import {
|
||||
BasePlugin,
|
||||
BasicRendererInfo,
|
||||
PluginInterface,
|
||||
RendererInfoResolveEventContext
|
||||
RendererInfoResolveEventContext,
|
||||
tipedLabel
|
||||
} from 'amis-editor-core';
|
||||
import {defaultValue, getSchemaTpl} from 'amis-editor-core';
|
||||
import {BUTTON_DEFAULT_ACTION, tipedLabel} from '../component/BaseControl';
|
||||
import {BUTTON_DEFAULT_ACTION} from '../component/BaseControl';
|
||||
import {getEventControlConfig} from '../util';
|
||||
import {RendererPluginAction, RendererPluginEvent} from 'amis-editor-core';
|
||||
import {SchemaObject} from 'amis/lib/Schema';
|
||||
|
@ -1,12 +1,13 @@
|
||||
import {registerEditorPlugin} from 'amis-editor-core';
|
||||
import {BasePlugin, RegionConfig, BaseEventContext} from 'amis-editor-core';
|
||||
import {
|
||||
BUTTON_DEFAULT_ACTION,
|
||||
formItemControl,
|
||||
tipedLabel
|
||||
} from '../component/BaseControl';
|
||||
import {defaultValue, getSchemaTpl} from 'amis-editor-core';
|
||||
import {RegionWrapper as Region} from 'amis-editor-core';
|
||||
BasePlugin,
|
||||
RegionConfig,
|
||||
BaseEventContext,
|
||||
tipedLabel,
|
||||
defaultValue,
|
||||
getSchemaTpl,
|
||||
registerEditorPlugin
|
||||
} from 'amis-editor-core';
|
||||
import {BUTTON_DEFAULT_ACTION} from '../component/BaseControl';
|
||||
|
||||
export class ButtonGroupPlugin extends BasePlugin {
|
||||
// 关联渲染器名字
|
||||
|
1681
packages/amis-editor/src/plugin/CRUD2.tsx
Normal file
1681
packages/amis-editor/src/plugin/CRUD2.tsx
Normal file
File diff suppressed because it is too large
Load Diff
@ -4,10 +4,13 @@ import {registerEditorPlugin} from 'amis-editor-core';
|
||||
import {
|
||||
BaseEventContext,
|
||||
BasePlugin,
|
||||
BasicRendererInfo,
|
||||
InsertEventContext,
|
||||
PluginEvent,
|
||||
PluginInterface,
|
||||
RegionConfig,
|
||||
RendererInfo,
|
||||
RendererInfoResolveEventContext,
|
||||
VRendererConfig
|
||||
} from 'amis-editor-core';
|
||||
import {defaultValue, getSchemaTpl} from 'amis-editor-core';
|
||||
@ -204,6 +207,8 @@ export class CardPlugin extends BasePlugin {
|
||||
}*/
|
||||
|
||||
fieldWrapperResolve = (dom: HTMLElement) => dom;
|
||||
|
||||
|
||||
overrides = {
|
||||
renderFeild: function (
|
||||
this: any,
|
||||
|
104
packages/amis-editor/src/plugin/Card2.tsx
Normal file
104
packages/amis-editor/src/plugin/Card2.tsx
Normal file
@ -0,0 +1,104 @@
|
||||
import {
|
||||
BaseEventContext,
|
||||
BasePlugin,
|
||||
RegionConfig,
|
||||
defaultValue,
|
||||
getSchemaTpl,
|
||||
tipedLabel,
|
||||
registerEditorPlugin
|
||||
} from 'amis-editor-core';
|
||||
|
||||
export class Card2Plugin extends BasePlugin {
|
||||
// 关联渲染器名字
|
||||
rendererName = 'card2';
|
||||
$schema = '/schemas/Card2Schema.json';
|
||||
|
||||
// 组件名称
|
||||
name = '卡片';
|
||||
isBaseComponent = true;
|
||||
description = '展示单个卡片。';
|
||||
tags = ['展示'];
|
||||
icon = '';
|
||||
scaffold = {
|
||||
type: 'card2',
|
||||
body: '内容'
|
||||
};
|
||||
previewSchema = {
|
||||
...this.scaffold
|
||||
};
|
||||
|
||||
regions: Array<RegionConfig> = [
|
||||
{
|
||||
key: 'body',
|
||||
label: '内容区',
|
||||
renderMethod: 'renderBody',
|
||||
preferTag: '展示'
|
||||
}
|
||||
];
|
||||
|
||||
panelTitle = '卡片';
|
||||
|
||||
panelJustify = true;
|
||||
|
||||
panelBodyCreator = (context: BaseEventContext) => {
|
||||
return [
|
||||
getSchemaTpl('tabs', [
|
||||
{
|
||||
title: '属性',
|
||||
body: getSchemaTpl('collapseGroup', [
|
||||
{
|
||||
title: '基本',
|
||||
body: [
|
||||
{
|
||||
type: 'button-group-select',
|
||||
label: tipedLabel(
|
||||
'选择区域',
|
||||
'点击触发选中或取消选中的区域'
|
||||
),
|
||||
name: 'checkOnItemClick',
|
||||
options: [
|
||||
{label: '整个', value: true},
|
||||
{label: '选框', value: false}
|
||||
],
|
||||
pipeIn: defaultValue(false)
|
||||
},
|
||||
getSchemaTpl('switch', {
|
||||
label: tipedLabel(
|
||||
'隐藏选框',
|
||||
'不再显示选择框,可以通过自定义选中态外观实现选中样式'
|
||||
),
|
||||
name: 'hideCheckToggler',
|
||||
visibleOn: 'this.checkOnItemClick'
|
||||
})
|
||||
]
|
||||
},
|
||||
getSchemaTpl('status', {isFormItem: false})
|
||||
])
|
||||
},
|
||||
{
|
||||
title: '外观',
|
||||
body: getSchemaTpl('collapseGroup', [
|
||||
getSchemaTpl('style:classNames', {
|
||||
isFormItem: false,
|
||||
schema: [
|
||||
getSchemaTpl('className', {
|
||||
name: 'bodyClassName',
|
||||
label: '内容区',
|
||||
visibleOn: 'this.icon'
|
||||
}),
|
||||
// TODO
|
||||
getSchemaTpl('className', {
|
||||
name: 'selectedClassName',
|
||||
label: '选中态',
|
||||
visibleOn: 'this.icon'
|
||||
})
|
||||
]
|
||||
})
|
||||
])
|
||||
}
|
||||
])
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
registerEditorPlugin(Card2Plugin);
|
@ -4,18 +4,17 @@ import {registerEditorPlugin} from 'amis-editor-core';
|
||||
import {
|
||||
BaseEventContext,
|
||||
BasePlugin,
|
||||
BasicPanelItem,
|
||||
BasicRendererInfo,
|
||||
BasicToolbarItem,
|
||||
ContextMenuEventContext,
|
||||
ContextMenuItem,
|
||||
PluginInterface,
|
||||
RegionConfig,
|
||||
RendererInfo,
|
||||
RendererInfoResolveEventContext
|
||||
RendererInfoResolveEventContext,
|
||||
tipedLabel
|
||||
} from 'amis-editor-core';
|
||||
import {defaultValue, getSchemaTpl} from 'amis-editor-core';
|
||||
import {diff, JSONPipeOut, repeatArray} from 'amis-editor-core';
|
||||
import {getEventControlConfig} from '../util';
|
||||
|
||||
export class CardsPlugin extends BasePlugin {
|
||||
// 关联渲染器名字
|
||||
@ -41,26 +40,17 @@ export class CardsPlugin extends BasePlugin {
|
||||
},
|
||||
columnsCount: 2,
|
||||
card: {
|
||||
type: 'card',
|
||||
type: 'card2',
|
||||
className: 'm-b-none',
|
||||
header: {
|
||||
title: '标题',
|
||||
subTitle: '副标题'
|
||||
},
|
||||
body: [
|
||||
{
|
||||
name: 'a',
|
||||
label: 'A'
|
||||
},
|
||||
{
|
||||
name: 'b',
|
||||
label: 'B'
|
||||
}
|
||||
],
|
||||
actions: [
|
||||
{
|
||||
label: '详情',
|
||||
type: 'button'
|
||||
type: 'container',
|
||||
body: [
|
||||
{
|
||||
type: 'tpl',
|
||||
tpl: '这是一个模板'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -71,116 +61,119 @@ export class CardsPlugin extends BasePlugin {
|
||||
};
|
||||
|
||||
panelTitle = '卡片集';
|
||||
|
||||
panelJustify = true;
|
||||
|
||||
panelBodyCreator = (context: BaseEventContext) => {
|
||||
const isCRUDBody = context.schema.type === 'crud';
|
||||
return [
|
||||
getSchemaTpl('tabs', [
|
||||
{
|
||||
title: '常规',
|
||||
body: [
|
||||
{
|
||||
children: (
|
||||
<div className="m-b">
|
||||
<Button
|
||||
level="success"
|
||||
size="sm"
|
||||
block
|
||||
onClick={this.editDetail.bind(this, context.id)}
|
||||
>
|
||||
配置单项信息
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
|
||||
{
|
||||
type: 'divider'
|
||||
},
|
||||
{
|
||||
name: 'title',
|
||||
type: 'input-text',
|
||||
label: '标题'
|
||||
},
|
||||
{
|
||||
name: 'href',
|
||||
type: 'input-text',
|
||||
label: '打开外部链接'
|
||||
},
|
||||
isCRUDBody
|
||||
? null
|
||||
: {
|
||||
name: 'source',
|
||||
type: 'input-text',
|
||||
label: '数据源',
|
||||
pipeIn: defaultValue('${items}'),
|
||||
description: '绑定当前环境变量',
|
||||
test: !isCRUDBody
|
||||
},
|
||||
{
|
||||
name: 'placeholder',
|
||||
value: '暂无数据',
|
||||
type: 'input-text',
|
||||
label: '无数据提示'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '外观',
|
||||
body: [
|
||||
getSchemaTpl('switch', {
|
||||
name: 'showHeader',
|
||||
label: '是否显示头部',
|
||||
pipeIn: defaultValue(true)
|
||||
}),
|
||||
|
||||
getSchemaTpl('switch', {
|
||||
name: 'showFooter',
|
||||
label: '是否显示底部',
|
||||
pipeIn: defaultValue(true)
|
||||
}),
|
||||
|
||||
getSchemaTpl('className', {
|
||||
label: 'CSS 类名'
|
||||
}),
|
||||
getSchemaTpl('className', {
|
||||
name: 'headerClassName',
|
||||
label: '头部 CSS 类名'
|
||||
}),
|
||||
getSchemaTpl('className', {
|
||||
name: 'footerClassName',
|
||||
label: '底部 CSS 类名'
|
||||
}),
|
||||
getSchemaTpl('className', {
|
||||
name: 'itemsClassName',
|
||||
label: '内容 CSS 类名'
|
||||
}),
|
||||
getSchemaTpl('className', {
|
||||
pipeIn: defaultValue('Grid-col--sm6 Grid-col--md4 Grid-col--lg3'),
|
||||
name: 'itemClassName',
|
||||
label: '卡片 CSS 类名'
|
||||
}),
|
||||
{
|
||||
name: 'columnsCount',
|
||||
type: 'input-range',
|
||||
visibleOn: '!this.leftFixed',
|
||||
min: 0,
|
||||
max: 12,
|
||||
step: 1,
|
||||
label: '每行显示个数',
|
||||
description: '不设置时,由卡片 CSS 类名决定'
|
||||
},
|
||||
getSchemaTpl('switch', {
|
||||
name: 'masonryLayout',
|
||||
label: '启用瀑布流'
|
||||
})
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '显隐',
|
||||
body: [getSchemaTpl('ref'), getSchemaTpl('visible')]
|
||||
}
|
||||
])
|
||||
];
|
||||
const isCRUDBody = ['crud', 'crud2'].includes(context.schema.type);
|
||||
|
||||
return getSchemaTpl('tabs', [
|
||||
{
|
||||
title: '属性',
|
||||
body: getSchemaTpl('collapseGroup', [
|
||||
{
|
||||
title: '基本',
|
||||
body: [
|
||||
getSchemaTpl('switch', {
|
||||
label: '可多选',
|
||||
name: 'multiple',
|
||||
visibleOn: `data.selectable`
|
||||
}),
|
||||
// getSchemaTpl('switch', {
|
||||
// label: '可全选',
|
||||
// name: 'checkAll',
|
||||
// pipeIn: defaultValue(true),
|
||||
// visibleOn: `data.selectable && data.multiple`
|
||||
// }),
|
||||
{
|
||||
name: 'placeholder',
|
||||
value: '暂无数据',
|
||||
type: 'input-text',
|
||||
label: '占位内容'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '数据',
|
||||
hidden: isCRUDBody,
|
||||
body: [
|
||||
{
|
||||
name: 'source',
|
||||
type: 'input-text',
|
||||
label: tipedLabel('数据', '可绑定当前页面数据'),
|
||||
pipeIn: defaultValue('${items}'),
|
||||
// visible: !isCRUDBody
|
||||
},
|
||||
{
|
||||
name: 'valueField',
|
||||
type: 'input-text',
|
||||
label: '值字段',
|
||||
// visible: isInForm && !isCRUDBody
|
||||
},
|
||||
]
|
||||
},
|
||||
getSchemaTpl('status', {
|
||||
isFormItem: false
|
||||
})
|
||||
])
|
||||
},
|
||||
{
|
||||
title: '外观',
|
||||
body: getSchemaTpl('collapseGroup', [
|
||||
{
|
||||
title: '布局',
|
||||
body: [
|
||||
{
|
||||
type: 'button-group-select',
|
||||
name: 'masonryLayout',
|
||||
label: '模式',
|
||||
pipeIn: defaultValue(false),
|
||||
options: [
|
||||
{label: '瀑布', value: true},
|
||||
{label: '流式', value: false}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'columnsCount',
|
||||
type: 'input-range',
|
||||
pipeIn: defaultValue(4),
|
||||
min: 0,
|
||||
max: 12,
|
||||
step: 1,
|
||||
label: tipedLabel(
|
||||
'每行显示个数',
|
||||
'不设置时,由卡片 CSS 类名决定'
|
||||
)
|
||||
}
|
||||
]
|
||||
},
|
||||
getSchemaTpl('style:classNames', {
|
||||
isFormItem: false,
|
||||
schema: [
|
||||
getSchemaTpl('className', {
|
||||
name: 'itemsClassName',
|
||||
label: '内容'
|
||||
}),
|
||||
getSchemaTpl('className', {
|
||||
pipeIn: defaultValue('Grid-col--sm6 Grid-col--md4 Grid-col--lg3'),
|
||||
name: 'itemClassName',
|
||||
label: '卡片'
|
||||
}),
|
||||
]
|
||||
})
|
||||
])
|
||||
},
|
||||
{
|
||||
title: '事件',
|
||||
className: 'p-none',
|
||||
body: [
|
||||
getSchemaTpl('eventControl', {
|
||||
name: 'onEvent',
|
||||
...getEventControlConfig(this.manager, context)
|
||||
})
|
||||
]
|
||||
}
|
||||
]);
|
||||
};
|
||||
|
||||
editDetail(id: string) {
|
||||
@ -253,14 +246,16 @@ export class CardsPlugin extends BasePlugin {
|
||||
...props.defaultData,
|
||||
...props.data
|
||||
};
|
||||
const arr = Array.isArray(props.value)
|
||||
let value = Array.isArray(props.value)
|
||||
? props.value
|
||||
: typeof props.source === 'string'
|
||||
? resolveVariable(props.source, data)
|
||||
: resolveVariable('items', data);
|
||||
|
||||
if (!Array.isArray(arr) || !arr.length) {
|
||||
const mockedData: any = {
|
||||
? resolveVariable(props.source, data)
|
||||
: resolveVariable('items', data);
|
||||
|
||||
value = !Array.isArray(value) ? [] : value;
|
||||
|
||||
if (value.length < 5) {
|
||||
const mockedData: any = value.length ? value[0] : {
|
||||
id: 666,
|
||||
title: '假数据',
|
||||
description: '假数据',
|
||||
@ -268,20 +263,36 @@ export class CardsPlugin extends BasePlugin {
|
||||
b: '假数据'
|
||||
};
|
||||
|
||||
props.value = repeatArray(mockedData, 1).map((item, index) => ({
|
||||
value = value.concat(repeatArray(mockedData, 3).map((item, index) => ({
|
||||
...item,
|
||||
id: index + 1
|
||||
}));
|
||||
})));
|
||||
}
|
||||
|
||||
const {$schema, ...rest} = props;
|
||||
|
||||
value = value.slice(0, 4);
|
||||
|
||||
return {
|
||||
...JSONPipeOut(rest),
|
||||
$schema
|
||||
...props,
|
||||
value
|
||||
};
|
||||
}
|
||||
|
||||
overrides = {
|
||||
renderCard(
|
||||
this: any,
|
||||
index: number,
|
||||
card: any,
|
||||
...rest: any[]
|
||||
) {
|
||||
return this.super(
|
||||
index,
|
||||
// 使第一个卡片元素可以选择并编辑schema
|
||||
index > 0 ? JSONPipeOut(card) : card,
|
||||
...rest
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
getRendererInfo(
|
||||
context: RendererInfoResolveEventContext
|
||||
): BasicRendererInfo | void {
|
||||
@ -289,7 +300,7 @@ export class CardsPlugin extends BasePlugin {
|
||||
const {renderer, schema} = context;
|
||||
if (
|
||||
!schema.$$id &&
|
||||
schema.$$editor?.renderer.name === 'crud' &&
|
||||
['crud', 'crud2'].includes(schema.$$editor?.renderer.name) &&
|
||||
renderer.name === 'cards'
|
||||
) {
|
||||
return {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {registerEditorPlugin} from 'amis-editor-core';
|
||||
import {BasePlugin, RegionConfig, BaseEventContext} from 'amis-editor-core';
|
||||
import {defaultValue, getSchemaTpl} from 'amis-editor-core';
|
||||
import {tipedLabel} from '../component/BaseControl';
|
||||
import {tipedLabel} from 'amis-editor-core';
|
||||
|
||||
export class CollapsePlugin extends BasePlugin {
|
||||
// 关联渲染器名字
|
||||
|
@ -2,7 +2,7 @@ import {registerEditorPlugin} from 'amis-editor-core';
|
||||
import {BasePlugin, RegionConfig, BaseEventContext} from 'amis-editor-core';
|
||||
import {defaultValue, getSchemaTpl} from 'amis-editor-core';
|
||||
|
||||
import {tipedLabel} from '../component/BaseControl';
|
||||
import {tipedLabel} from 'amis-editor-core';
|
||||
import {isObject} from 'amis-editor-core';
|
||||
|
||||
export class CollapseGroupPlugin extends BasePlugin {
|
||||
|
129
packages/amis-editor/src/plugin/ColumnToggler.tsx
Normal file
129
packages/amis-editor/src/plugin/ColumnToggler.tsx
Normal file
@ -0,0 +1,129 @@
|
||||
import {
|
||||
BaseEventContext,
|
||||
BasePlugin,
|
||||
BasicRendererInfo,
|
||||
PluginInterface,
|
||||
RendererInfoResolveEventContext,
|
||||
getSchemaTpl,
|
||||
registerEditorPlugin
|
||||
} from 'amis-editor-core';
|
||||
|
||||
export class ColumnToggler extends BasePlugin {
|
||||
// 关联渲染器名字
|
||||
rendererName = 'column-toggler';
|
||||
$schema = '/schemas/ColumnToggler.json';
|
||||
|
||||
// 组件名称
|
||||
name = '自定义显示列';
|
||||
isBaseComponent = true;
|
||||
description =
|
||||
'用来展示表格的自定义显示列按钮,你可以配置不同的展示样式。';
|
||||
|
||||
tags = ['自定义显示列'];
|
||||
icon = 'fa fa-square';
|
||||
|
||||
panelTitle = '自定义显示列';
|
||||
|
||||
panelJustify = true;
|
||||
|
||||
panelBodyCreator = (context: BaseEventContext) => {
|
||||
return getSchemaTpl('tabs', [
|
||||
{
|
||||
title: '属性',
|
||||
body: getSchemaTpl('collapseGroup', [
|
||||
{
|
||||
title: '基本',
|
||||
body: [
|
||||
{
|
||||
label: '按钮文字',
|
||||
type: 'input-text',
|
||||
name: 'label'
|
||||
},
|
||||
{
|
||||
label: '按钮提示',
|
||||
type: 'input-text',
|
||||
name: 'tooltip'
|
||||
},
|
||||
getSchemaTpl('switch', {
|
||||
name: 'defaultIsOpened',
|
||||
label: '是否默认展开'
|
||||
}),
|
||||
getSchemaTpl('icon', {
|
||||
label: '按钮图标'
|
||||
})
|
||||
]
|
||||
}
|
||||
])
|
||||
},
|
||||
{
|
||||
title: '外观',
|
||||
body: getSchemaTpl('collapseGroup', [
|
||||
{
|
||||
title: '基本',
|
||||
body: [
|
||||
getSchemaTpl('size', {
|
||||
label: '按钮尺寸'
|
||||
})
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'CSS 类名',
|
||||
body: [
|
||||
getSchemaTpl('className', {
|
||||
name: 'className',
|
||||
label: '显示列样式'
|
||||
}),
|
||||
|
||||
getSchemaTpl('className', {
|
||||
name: 'btnClassName',
|
||||
label: '按钮样式'
|
||||
}),
|
||||
]
|
||||
}
|
||||
])
|
||||
}
|
||||
]);
|
||||
};
|
||||
|
||||
/**
|
||||
* 如果禁用了没办法编辑
|
||||
*/
|
||||
filterProps(props: any) {
|
||||
props.disabled = false;
|
||||
return props;
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果配置里面有 rendererName 自动返回渲染器信息。
|
||||
* @param renderer
|
||||
*/
|
||||
getRendererInfo({
|
||||
renderer,
|
||||
schema
|
||||
}: RendererInfoResolveEventContext): BasicRendererInfo | void {
|
||||
const plugin: PluginInterface = this;
|
||||
|
||||
if (
|
||||
schema.$$id &&
|
||||
plugin.name &&
|
||||
plugin.rendererName &&
|
||||
plugin.rendererName === renderer.name
|
||||
) {
|
||||
// 复制部分信息出去
|
||||
return {
|
||||
name: schema.label ? schema.label : plugin.name,
|
||||
regions: plugin.regions,
|
||||
patchContainers: plugin.patchContainers,
|
||||
// wrapper: plugin.wrapper,
|
||||
vRendererConfig: plugin.vRendererConfig,
|
||||
wrapperProps: plugin.wrapperProps,
|
||||
wrapperResolve: plugin.wrapperResolve,
|
||||
filterProps: plugin.filterProps,
|
||||
$schema: plugin.$schema,
|
||||
renderRenderer: plugin.renderRenderer
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
registerEditorPlugin(ColumnToggler);
|
@ -12,11 +12,17 @@ export class ContainerPlugin extends BasePlugin {
|
||||
isBaseComponent = true;
|
||||
description = '一个简单的容器,可以将多个渲染器放置在一起。';
|
||||
tags = ['容器'];
|
||||
withDataSource = false;
|
||||
icon = 'fa fa-square-o';
|
||||
pluginIcon = 'container-plugin';
|
||||
scaffold = {
|
||||
type: 'container',
|
||||
body: '内容'
|
||||
body: [
|
||||
{
|
||||
type: 'tpl',
|
||||
tpl: '内容'
|
||||
}
|
||||
]
|
||||
};
|
||||
previewSchema = {
|
||||
...this.scaffold
|
||||
|
@ -1,20 +1,18 @@
|
||||
import {Button} from 'amis';
|
||||
import React from 'react';
|
||||
import {registerEditorPlugin} from 'amis-editor-core';
|
||||
import {
|
||||
BaseEventContext,
|
||||
BasePlugin,
|
||||
BasicToolbarItem,
|
||||
ContextMenuEventContext,
|
||||
ContextMenuItem
|
||||
ContextMenuItem,
|
||||
registerEditorPlugin,
|
||||
tipedLabel,
|
||||
defaultValue,
|
||||
getSchemaTpl,
|
||||
diff
|
||||
} from 'amis-editor-core';
|
||||
import {defaultValue, getSchemaTpl} from 'amis-editor-core';
|
||||
import {diff} from 'amis-editor-core';
|
||||
import {
|
||||
BUTTON_DEFAULT_ACTION,
|
||||
formItemControl,
|
||||
tipedLabel
|
||||
} from '../component/BaseControl';
|
||||
import {BUTTON_DEFAULT_ACTION} from '../component/BaseControl';
|
||||
export class DropDownButtonPlugin extends BasePlugin {
|
||||
// 关联渲染器名字
|
||||
rendererName = 'dropdown-button';
|
||||
|
@ -3,10 +3,10 @@ import {BasePlugin, BaseEventContext} from 'amis-editor-core';
|
||||
|
||||
import {
|
||||
RendererPluginAction,
|
||||
RendererPluginEvent
|
||||
RendererPluginEvent,
|
||||
tipedLabel
|
||||
} from 'amis-editor-core';
|
||||
import {getSchemaTpl, defaultValue} from 'amis-editor-core';
|
||||
import {tipedLabel} from '../../component/BaseControl';
|
||||
import {getEventControlConfig} from '../../util';
|
||||
|
||||
export class ButtonGroupControlPlugin extends BasePlugin {
|
||||
@ -118,17 +118,15 @@ export class ButtonGroupControlPlugin extends BasePlugin {
|
||||
rendererSchema: context?.schema,
|
||||
useSelectMode: true, // 改用 Select 设置模式
|
||||
visibleOn: 'this.options && this.options.length > 0'
|
||||
}),
|
||||
})
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '按钮管理',
|
||||
body: [
|
||||
getSchemaTpl('optionControlV2'),
|
||||
]
|
||||
body: [getSchemaTpl('optionControlV2')]
|
||||
},
|
||||
getSchemaTpl('status', {
|
||||
isFormItem: true,
|
||||
isFormItem: true
|
||||
})
|
||||
])
|
||||
]
|
||||
@ -172,10 +170,10 @@ export class ButtonGroupControlPlugin extends BasePlugin {
|
||||
getSchemaTpl('className', {
|
||||
label: '按钮',
|
||||
name: 'btnClassName'
|
||||
}),
|
||||
})
|
||||
]
|
||||
}),
|
||||
]),
|
||||
})
|
||||
])
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -4,16 +4,15 @@ import {
|
||||
BaseEventContext,
|
||||
BasicSubRenderInfo,
|
||||
RendererEventContext,
|
||||
SubRendererInfo
|
||||
} from 'amis-editor-core';
|
||||
import {getSchemaTpl, defaultValue} from 'amis-editor-core';
|
||||
import {ValidatorTag} from '../../validator';
|
||||
import {tipedLabel} from '../../component/BaseControl';
|
||||
import {getEventControlConfig} from '../../util';
|
||||
import {
|
||||
SubRendererInfo,
|
||||
RendererPluginAction,
|
||||
RendererPluginEvent
|
||||
RendererPluginEvent,
|
||||
tipedLabel,
|
||||
getSchemaTpl,
|
||||
defaultValue
|
||||
} from 'amis-editor-core';
|
||||
import {ValidatorTag} from '../../validator';
|
||||
import {getEventControlConfig} from '../../util';
|
||||
|
||||
export class ChainedSelectControlPlugin extends BasePlugin {
|
||||
// 关联渲染器名字
|
||||
@ -135,7 +134,8 @@ export class ChainedSelectControlPlugin extends BasePlugin {
|
||||
getSchemaTpl('labelRemark'),
|
||||
getSchemaTpl('remark'),
|
||||
getSchemaTpl('placeholder'),
|
||||
getSchemaTpl('description')
|
||||
getSchemaTpl('description'),
|
||||
getSchemaTpl('autoFillApi')
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -10,14 +10,12 @@ import {
|
||||
BasicSubRenderInfo,
|
||||
RendererEventContext,
|
||||
SubRendererInfo,
|
||||
BaseEventContext
|
||||
BaseEventContext,
|
||||
tipedLabel
|
||||
} from 'amis-editor-core';
|
||||
import {ValidatorTag} from '../../validator';
|
||||
import {tipedLabel} from '../../component/BaseControl';
|
||||
import {
|
||||
RendererPluginAction,
|
||||
RendererPluginEvent
|
||||
} from 'amis-editor-core';
|
||||
|
||||
import {RendererPluginAction, RendererPluginEvent} from 'amis-editor-core';
|
||||
import {getEventControlConfig} from '../../util';
|
||||
|
||||
setSchemaTpl('option', {
|
||||
@ -110,7 +108,7 @@ export class CheckboxControlPlugin extends BasePlugin {
|
||||
getSchemaTpl('label'),
|
||||
getSchemaTpl('option'),
|
||||
{
|
||||
type: 'ae-Switch-More',
|
||||
type: 'ae-switch-more',
|
||||
hiddenOnDefault: false,
|
||||
mode: 'normal',
|
||||
label: '值格式',
|
||||
@ -152,7 +150,8 @@ export class CheckboxControlPlugin extends BasePlugin {
|
||||
}),
|
||||
getSchemaTpl('labelRemark'),
|
||||
getSchemaTpl('remark'),
|
||||
getSchemaTpl('description')
|
||||
getSchemaTpl('description'),
|
||||
getSchemaTpl('autoFillApi')
|
||||
]
|
||||
},
|
||||
getSchemaTpl('status', {isFormItem: true}),
|
||||
|
@ -168,7 +168,8 @@ export class CheckboxesControlPlugin extends BasePlugin {
|
||||
getSchemaTpl('extractValue'),
|
||||
getSchemaTpl('labelRemark'),
|
||||
getSchemaTpl('remark'),
|
||||
getSchemaTpl('description')
|
||||
getSchemaTpl('description'),
|
||||
getSchemaTpl('autoFillApi')
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -140,7 +140,8 @@ export class CodeEditorControlPlugin extends BasePlugin {
|
||||
}),
|
||||
getSchemaTpl('labelRemark'),
|
||||
getSchemaTpl('remark'),
|
||||
getSchemaTpl('description')
|
||||
getSchemaTpl('description'),
|
||||
getSchemaTpl('autoFillApi')
|
||||
]
|
||||
},
|
||||
getSchemaTpl('status', {isFormItem: true}),
|
||||
|
@ -149,7 +149,8 @@ export class DiffEditorControlPlugin extends BasePlugin {
|
||||
},
|
||||
getSchemaTpl('labelRemark'),
|
||||
getSchemaTpl('remark'),
|
||||
getSchemaTpl('description')
|
||||
getSchemaTpl('description'),
|
||||
getSchemaTpl('autoFillApi')
|
||||
]
|
||||
},
|
||||
getSchemaTpl('status', {isFormItem: true}),
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -9,10 +9,7 @@ import {
|
||||
} from 'amis-editor-core';
|
||||
|
||||
import {formItemControl} from '../../component/BaseControl';
|
||||
import {
|
||||
RendererPluginAction,
|
||||
RendererPluginEvent
|
||||
} from 'amis-editor-core';
|
||||
import {RendererPluginAction, RendererPluginEvent} from 'amis-editor-core';
|
||||
|
||||
export class CityControlPlugin extends BasePlugin {
|
||||
// 关联渲染器名字
|
||||
|
@ -1,9 +1,8 @@
|
||||
import {registerEditorPlugin} from 'amis-editor-core';
|
||||
import {registerEditorPlugin, tipedLabel} from 'amis-editor-core';
|
||||
import {getSchemaTpl} from 'amis-editor-core';
|
||||
import {ValidatorTag} from '../../validator';
|
||||
import {BasePlugin, BaseEventContext} from 'amis-editor-core';
|
||||
import {getEventControlConfig} from '../../util';
|
||||
import {tipedLabel} from '../../component/BaseControl';
|
||||
import tinyColor from 'tinycolor2';
|
||||
|
||||
function convertColor(value: string[], format: string): string[];
|
||||
@ -171,124 +170,133 @@ export class ColorControlPlugin extends BasePlugin {
|
||||
return getSchemaTpl('tabs', [
|
||||
{
|
||||
title: '属性',
|
||||
body: getSchemaTpl('collapseGroup', [
|
||||
{
|
||||
title: '基本',
|
||||
body: [
|
||||
getSchemaTpl('formItemName', {
|
||||
required: true
|
||||
}),
|
||||
getSchemaTpl('label'),
|
||||
{
|
||||
type: 'select',
|
||||
label: '值格式',
|
||||
name: 'format',
|
||||
value: 'hex',
|
||||
options: formatOptions,
|
||||
onChange: (
|
||||
format: any,
|
||||
oldFormat: any,
|
||||
model: any,
|
||||
form: any
|
||||
) => {
|
||||
const {value, presetColors} = form.data;
|
||||
if (value) {
|
||||
form.setValueByName('value', convertColor(value, format));
|
||||
body: getSchemaTpl(
|
||||
'collapseGroup',
|
||||
[
|
||||
{
|
||||
title: '基本',
|
||||
body: [
|
||||
getSchemaTpl('formItemName', {
|
||||
required: true
|
||||
}),
|
||||
getSchemaTpl('label'),
|
||||
{
|
||||
type: 'select',
|
||||
label: '值格式',
|
||||
name: 'format',
|
||||
value: 'hex',
|
||||
options: formatOptions,
|
||||
onChange: (
|
||||
format: any,
|
||||
oldFormat: any,
|
||||
model: any,
|
||||
form: any
|
||||
) => {
|
||||
const {value, presetColors} = form.data;
|
||||
if (value) {
|
||||
form.setValueByName('value', convertColor(value, format));
|
||||
}
|
||||
if (Array.isArray(presetColors)) {
|
||||
form.setValueByName(
|
||||
'presetColors',
|
||||
convertColor(presetColors, format)
|
||||
);
|
||||
}
|
||||
}
|
||||
if (Array.isArray(presetColors)) {
|
||||
form.setValueByName(
|
||||
'presetColors',
|
||||
convertColor(presetColors, format)
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
// todo: 待优化
|
||||
[
|
||||
...formatOptions.map(({value}) =>
|
||||
this.getConditionalColorPanel(value)
|
||||
)
|
||||
],
|
||||
// {
|
||||
// label: '默认值',
|
||||
// name: 'value',
|
||||
// type: 'input-color',
|
||||
// format: '${format}'
|
||||
// },
|
||||
getSchemaTpl('clearable'),
|
||||
getSchemaTpl('labelRemark'),
|
||||
getSchemaTpl('remark'),
|
||||
getSchemaTpl('placeholder'),
|
||||
getSchemaTpl('description')
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '拾色器',
|
||||
body: [
|
||||
getSchemaTpl('switch', {
|
||||
label: tipedLabel(
|
||||
'隐藏调色盘',
|
||||
'开启时,禁止手动输入颜色,只能从备选颜色中选择'
|
||||
),
|
||||
name: 'allowCustomColor',
|
||||
disabledOn:
|
||||
'Array.isArray(presetColors) && presetColors.length === 0',
|
||||
pipeIn: (value: any) =>
|
||||
typeof value === 'undefined' ? false : !value,
|
||||
pipeOut: (value: boolean) => !value
|
||||
}),
|
||||
getSchemaTpl('switch', {
|
||||
label: tipedLabel('备选色', '拾色器底部的备选颜色'),
|
||||
name: 'presetColors',
|
||||
onText: '自定义',
|
||||
offText: '默认',
|
||||
pipeIn: (value: any) =>
|
||||
typeof value === 'undefined' ? false : true,
|
||||
pipeOut: (
|
||||
value: any,
|
||||
originValue: any,
|
||||
{format = 'hex'}: any
|
||||
) => {
|
||||
return !value ? undefined : presetColorsByFormat[format];
|
||||
},
|
||||
onChange: (
|
||||
colors: any,
|
||||
oldValue: any,
|
||||
model: any,
|
||||
form: any
|
||||
) => {
|
||||
if (Array.isArray(colors) && colors.length === 0) {
|
||||
form.setValueByName('allowCustomColor', true);
|
||||
// todo: 待优化
|
||||
[
|
||||
...formatOptions.map(({value}) =>
|
||||
this.getConditionalColorPanel(value)
|
||||
)
|
||||
],
|
||||
// {
|
||||
// label: '默认值',
|
||||
// name: 'value',
|
||||
// type: 'input-color',
|
||||
// format: '${format}'
|
||||
// },
|
||||
getSchemaTpl('clearable'),
|
||||
getSchemaTpl('labelRemark'),
|
||||
getSchemaTpl('remark'),
|
||||
getSchemaTpl('placeholder'),
|
||||
getSchemaTpl('description'),
|
||||
getSchemaTpl('autoFillApi')
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '拾色器',
|
||||
body: [
|
||||
getSchemaTpl('switch', {
|
||||
label: tipedLabel(
|
||||
'隐藏调色盘',
|
||||
'开启时,禁止手动输入颜色,只能从备选颜色中选择'
|
||||
),
|
||||
name: 'allowCustomColor',
|
||||
disabledOn:
|
||||
'Array.isArray(presetColors) && presetColors.length === 0',
|
||||
pipeIn: (value: any) =>
|
||||
typeof value === 'undefined' ? false : !value,
|
||||
pipeOut: (value: boolean) => !value
|
||||
}),
|
||||
getSchemaTpl('switch', {
|
||||
label: tipedLabel('备选色', '拾色器底部的备选颜色'),
|
||||
name: 'presetColors',
|
||||
onText: '自定义',
|
||||
offText: '默认',
|
||||
pipeIn: (value: any) =>
|
||||
typeof value === 'undefined' ? false : true,
|
||||
pipeOut: (
|
||||
value: any,
|
||||
originValue: any,
|
||||
{format = 'hex'}: any
|
||||
) => {
|
||||
return !value ? undefined : presetColorsByFormat[format];
|
||||
},
|
||||
onChange: (
|
||||
colors: any,
|
||||
oldValue: any,
|
||||
model: any,
|
||||
form: any
|
||||
) => {
|
||||
if (Array.isArray(colors) && colors.length === 0) {
|
||||
form.setValueByName('allowCustomColor', true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
...formatOptions.map(({value}) =>
|
||||
this.getConditionalColorComb(value)
|
||||
)
|
||||
]
|
||||
},
|
||||
getSchemaTpl('status', {
|
||||
isFormItem: true
|
||||
}),
|
||||
getSchemaTpl('validation', {
|
||||
tag: ValidatorTag.MultiSelect
|
||||
})
|
||||
], {...context?.schema, configTitle: 'props'})
|
||||
}),
|
||||
...formatOptions.map(({value}) =>
|
||||
this.getConditionalColorComb(value)
|
||||
)
|
||||
]
|
||||
},
|
||||
getSchemaTpl('status', {
|
||||
isFormItem: true
|
||||
}),
|
||||
getSchemaTpl('validation', {
|
||||
tag: ValidatorTag.MultiSelect
|
||||
})
|
||||
],
|
||||
{...context?.schema, configTitle: 'props'}
|
||||
)
|
||||
},
|
||||
{
|
||||
title: '外观',
|
||||
body: getSchemaTpl('collapseGroup', [
|
||||
getSchemaTpl('style:formItem', {renderer}),
|
||||
getSchemaTpl('style:classNames', {
|
||||
schema: [
|
||||
getSchemaTpl('className', {
|
||||
label: '描述',
|
||||
name: 'descriptionClassName',
|
||||
visibleOn: 'this.description'
|
||||
})
|
||||
]
|
||||
})
|
||||
], {...context?.schema, configTitle: 'style'})
|
||||
body: getSchemaTpl(
|
||||
'collapseGroup',
|
||||
[
|
||||
getSchemaTpl('style:formItem', {renderer}),
|
||||
getSchemaTpl('style:classNames', {
|
||||
schema: [
|
||||
getSchemaTpl('className', {
|
||||
label: '描述',
|
||||
name: 'descriptionClassName',
|
||||
visibleOn: 'this.description'
|
||||
})
|
||||
]
|
||||
})
|
||||
],
|
||||
{...context?.schema, configTitle: 'style'}
|
||||
)
|
||||
},
|
||||
{
|
||||
title: '事件',
|
||||
|
@ -1,14 +1,10 @@
|
||||
import {registerEditorPlugin} from 'amis-editor-core';
|
||||
import {defaultValue, getSchemaTpl} from 'amis-editor-core';
|
||||
import {BasePlugin, BaseEventContext} from 'amis-editor-core';
|
||||
import {BasePlugin, BaseEventContext, tipedLabel} from 'amis-editor-core';
|
||||
|
||||
import {tipedLabel} from '../../component/BaseControl';
|
||||
import {ValidatorTag} from '../../validator';
|
||||
import {getEventControlConfig} from '../../util';
|
||||
import {
|
||||
RendererPluginAction,
|
||||
RendererPluginEvent
|
||||
} from 'amis-editor-core';
|
||||
import {RendererPluginAction, RendererPluginEvent} from 'amis-editor-core';
|
||||
|
||||
const formatX = [
|
||||
{
|
||||
@ -237,157 +233,166 @@ export class DateControlPlugin extends BasePlugin {
|
||||
return getSchemaTpl('tabs', [
|
||||
{
|
||||
title: '属性',
|
||||
body: getSchemaTpl('collapseGroup', [
|
||||
{
|
||||
title: '基本',
|
||||
body: [
|
||||
getSchemaTpl('formItemName', {
|
||||
required: true
|
||||
}),
|
||||
getSchemaTpl('label'),
|
||||
getSchemaTpl('selectDateType', {
|
||||
value: this.scaffold.type,
|
||||
onChange: (
|
||||
value: string,
|
||||
oldValue: any,
|
||||
model: any,
|
||||
form: any
|
||||
) => {
|
||||
let type: string = value.split('-')[1];
|
||||
body: getSchemaTpl(
|
||||
'collapseGroup',
|
||||
[
|
||||
{
|
||||
title: '基本',
|
||||
body: [
|
||||
getSchemaTpl('formItemName', {
|
||||
required: true
|
||||
}),
|
||||
getSchemaTpl('label'),
|
||||
getSchemaTpl('selectDateType', {
|
||||
value: this.scaffold.type,
|
||||
onChange: (
|
||||
value: string,
|
||||
oldValue: any,
|
||||
model: any,
|
||||
form: any
|
||||
) => {
|
||||
let type: string = value.split('-')[1];
|
||||
|
||||
form.setValues({
|
||||
inputFormat: DateType[type]?.format,
|
||||
placeholder: DateType[type]?.placeholder,
|
||||
format: type === 'time' ? 'HH:mm' : 'X',
|
||||
minDate: '',
|
||||
maxDate: '',
|
||||
value: ''
|
||||
});
|
||||
}
|
||||
}),
|
||||
{
|
||||
type: 'input-text',
|
||||
name: 'format',
|
||||
label: tipedLabel(
|
||||
'值格式',
|
||||
'提交数据前将根据设定格式化数据,请参考 <a href="https://momentjs.com/" target="_blank">moment</a> 中的格式用法。'
|
||||
),
|
||||
pipeIn: defaultValue('X')
|
||||
},
|
||||
{
|
||||
type: 'input-text',
|
||||
name: 'inputFormat',
|
||||
label: tipedLabel(
|
||||
'显示格式',
|
||||
'请参考 <a href="https://momentjs.com/" target="_blank">moment</a> 中的格式用法。'
|
||||
),
|
||||
pipeIn: defaultValue('YYYY-MM-DD'),
|
||||
clearable: true,
|
||||
onChange: (
|
||||
value: string,
|
||||
oldValue: any,
|
||||
model: any,
|
||||
form: any
|
||||
) => {
|
||||
const type = form.data.type.split('-')[1];
|
||||
model.setOptions(DateType[type].formatOptions);
|
||||
// 时间日期类组件 input-time 需要更加关注 timeFormat 和 inputFormat 属性区别
|
||||
// inputFormat 表示输入框内的显示格式; timeFormat表示选择下拉弹窗中展示"HH、mm、ss"的组合
|
||||
if (type === 'time') {
|
||||
const timeFormatObj = DateType[type].formatOptions.find(
|
||||
item => item.value === value
|
||||
);
|
||||
const timeFormat = timeFormatObj
|
||||
? (timeFormatObj as any).timeFormat
|
||||
: 'HH:mm:ss';
|
||||
form.setValues({
|
||||
timeFormat: timeFormat
|
||||
inputFormat: DateType[type]?.format,
|
||||
placeholder: DateType[type]?.placeholder,
|
||||
format: type === 'time' ? 'HH:mm' : 'X',
|
||||
minDate: '',
|
||||
maxDate: '',
|
||||
value: ''
|
||||
});
|
||||
}
|
||||
}),
|
||||
{
|
||||
type: 'input-text',
|
||||
name: 'format',
|
||||
label: tipedLabel(
|
||||
'值格式',
|
||||
'提交数据前将根据设定格式化数据,请参考 <a href="https://momentjs.com/" target="_blank">moment</a> 中的格式用法。'
|
||||
),
|
||||
pipeIn: defaultValue('X')
|
||||
},
|
||||
options:
|
||||
DateType[this.scaffold.type.split('-')[1]].formatOptions
|
||||
},
|
||||
getSchemaTpl('utc'),
|
||||
getSchemaTpl('clearable', {
|
||||
pipeIn: defaultValue(true)
|
||||
}),
|
||||
getSchemaTpl('valueFormula', {
|
||||
rendererSchema: context?.schema,
|
||||
label: tipedLabel(
|
||||
'默认值',
|
||||
'支持 <code>now、+1day、-2weeks、+1hours、+2years</code>等这种相对值用法'
|
||||
)
|
||||
}),
|
||||
getSchemaTpl('valueFormula', {
|
||||
name: 'minDate',
|
||||
rendererSchema: {
|
||||
...context?.schema,
|
||||
value: context?.schema.minDate
|
||||
{
|
||||
type: 'input-text',
|
||||
name: 'inputFormat',
|
||||
label: tipedLabel(
|
||||
'显示格式',
|
||||
'请参考 <a href="https://momentjs.com/" target="_blank">moment</a> 中的格式用法。'
|
||||
),
|
||||
pipeIn: defaultValue('YYYY-MM-DD'),
|
||||
clearable: true,
|
||||
onChange: (
|
||||
value: string,
|
||||
oldValue: any,
|
||||
model: any,
|
||||
form: any
|
||||
) => {
|
||||
const type = form.data.type.split('-')[1];
|
||||
model.setOptions(DateType[type].formatOptions);
|
||||
// 时间日期类组件 input-time 需要更加关注 timeFormat 和 inputFormat 属性区别
|
||||
// inputFormat 表示输入框内的显示格式; timeFormat表示选择下拉弹窗中展示"HH、mm、ss"的组合
|
||||
if (type === 'time') {
|
||||
const timeFormatObj = DateType[type].formatOptions.find(
|
||||
item => item.value === value
|
||||
);
|
||||
const timeFormat = timeFormatObj
|
||||
? (timeFormatObj as any).timeFormat
|
||||
: 'HH:mm:ss';
|
||||
form.setValues({
|
||||
timeFormat: timeFormat
|
||||
});
|
||||
}
|
||||
},
|
||||
options:
|
||||
DateType[this.scaffold.type.split('-')[1]].formatOptions
|
||||
},
|
||||
needDeleteProps: ['minDate'], // 避免自我限制
|
||||
label: tipedLabel('最小值', tipedLabelText)
|
||||
}),
|
||||
getSchemaTpl('valueFormula', {
|
||||
name: 'maxDate',
|
||||
rendererSchema: {
|
||||
...context?.schema,
|
||||
value: context?.schema.maxDate
|
||||
},
|
||||
needDeleteProps: ['maxDate'], // 避免自我限制
|
||||
label: tipedLabel('最大值', tipedLabelText)
|
||||
}),
|
||||
getSchemaTpl('placeholder', {
|
||||
pipeIn: defaultValue('请选择日期')
|
||||
}),
|
||||
// getSchemaTpl('remark'),
|
||||
// getSchemaTpl('labelRemark'),
|
||||
getSchemaTpl('description')
|
||||
]
|
||||
},
|
||||
getSchemaTpl('status', {isFormItem: true}),
|
||||
getSchemaTpl('validation', {
|
||||
tag: ValidatorTag.Date
|
||||
})
|
||||
], {...context?.schema, configTitle: 'props'})
|
||||
getSchemaTpl('utc'),
|
||||
getSchemaTpl('clearable', {
|
||||
pipeIn: defaultValue(true)
|
||||
}),
|
||||
getSchemaTpl('valueFormula', {
|
||||
rendererSchema: context?.schema,
|
||||
label: tipedLabel(
|
||||
'默认值',
|
||||
'支持 <code>now、+1day、-2weeks、+1hours、+2years</code>等这种相对值用法'
|
||||
)
|
||||
}),
|
||||
getSchemaTpl('valueFormula', {
|
||||
name: 'minDate',
|
||||
rendererSchema: {
|
||||
...context?.schema,
|
||||
value: context?.schema.minDate
|
||||
},
|
||||
needDeleteProps: ['minDate'], // 避免自我限制
|
||||
label: tipedLabel('最小值', tipedLabelText)
|
||||
}),
|
||||
getSchemaTpl('valueFormula', {
|
||||
name: 'maxDate',
|
||||
rendererSchema: {
|
||||
...context?.schema,
|
||||
value: context?.schema.maxDate
|
||||
},
|
||||
needDeleteProps: ['maxDate'], // 避免自我限制
|
||||
label: tipedLabel('最大值', tipedLabelText)
|
||||
}),
|
||||
getSchemaTpl('placeholder', {
|
||||
pipeIn: defaultValue('请选择日期')
|
||||
}),
|
||||
// getSchemaTpl('remark'),
|
||||
// getSchemaTpl('labelRemark'),
|
||||
getSchemaTpl('description'),
|
||||
getSchemaTpl('autoFillApi')
|
||||
]
|
||||
},
|
||||
getSchemaTpl('status', {isFormItem: true}),
|
||||
getSchemaTpl('validation', {
|
||||
tag: ValidatorTag.Date
|
||||
})
|
||||
],
|
||||
{...context?.schema, configTitle: 'props'}
|
||||
)
|
||||
},
|
||||
{
|
||||
title: '外观',
|
||||
body: getSchemaTpl('collapseGroup', [
|
||||
getSchemaTpl('style:formItem', renderer),
|
||||
getSchemaTpl('style:classNames', [
|
||||
getSchemaTpl('className', {
|
||||
label: '描述',
|
||||
name: 'descriptionClassName',
|
||||
visibleOn: 'this.description'
|
||||
}),
|
||||
getSchemaTpl('className', {
|
||||
name: 'addOn.className',
|
||||
label: 'AddOn',
|
||||
visibleOn: 'this.addOn && this.addOn.type === "text"'
|
||||
})
|
||||
]),
|
||||
getSchemaTpl('style:others', [
|
||||
{
|
||||
name: 'embed',
|
||||
type: 'button-group-select',
|
||||
size: 'md',
|
||||
label: '模式',
|
||||
mode: 'row',
|
||||
value: false,
|
||||
options: [
|
||||
{
|
||||
label: '浮层',
|
||||
value: false
|
||||
},
|
||||
{
|
||||
label: '内嵌',
|
||||
value: true
|
||||
}
|
||||
]
|
||||
}
|
||||
])
|
||||
], {...context?.schema, configTitle: 'style'})
|
||||
body: getSchemaTpl(
|
||||
'collapseGroup',
|
||||
[
|
||||
getSchemaTpl('style:formItem', renderer),
|
||||
getSchemaTpl('style:classNames', [
|
||||
getSchemaTpl('className', {
|
||||
label: '描述',
|
||||
name: 'descriptionClassName',
|
||||
visibleOn: 'this.description'
|
||||
}),
|
||||
getSchemaTpl('className', {
|
||||
name: 'addOn.className',
|
||||
label: 'AddOn',
|
||||
visibleOn: 'this.addOn && this.addOn.type === "text"'
|
||||
})
|
||||
]),
|
||||
getSchemaTpl('style:others', [
|
||||
{
|
||||
name: 'embed',
|
||||
type: 'button-group-select',
|
||||
size: 'md',
|
||||
label: '模式',
|
||||
mode: 'row',
|
||||
value: false,
|
||||
options: [
|
||||
{
|
||||
label: '浮层',
|
||||
value: false
|
||||
},
|
||||
{
|
||||
label: '内嵌',
|
||||
value: true
|
||||
}
|
||||
]
|
||||
}
|
||||
])
|
||||
],
|
||||
{...context?.schema, configTitle: 'style'}
|
||||
)
|
||||
},
|
||||
{
|
||||
title: '事件',
|
||||
|
@ -1,14 +1,10 @@
|
||||
import {defaultValue, getSchemaTpl} from 'amis-editor-core';
|
||||
import {defaultValue, getSchemaTpl, tipedLabel} from 'amis-editor-core';
|
||||
import {registerEditorPlugin} from 'amis-editor-core';
|
||||
import {BasePlugin, BaseEventContext} from 'amis-editor-core';
|
||||
|
||||
import {tipedLabel} from '../../component/BaseControl';
|
||||
import {ValidatorTag} from '../../validator';
|
||||
import {getEventControlConfig} from '../../util';
|
||||
import {
|
||||
RendererPluginAction,
|
||||
RendererPluginEvent
|
||||
} from 'amis-editor-core';
|
||||
import {RendererPluginAction, RendererPluginEvent} from 'amis-editor-core';
|
||||
|
||||
const DateType: {
|
||||
[key: string]: {
|
||||
@ -184,72 +180,74 @@ export class DateRangeControlPlugin extends BasePlugin {
|
||||
return getSchemaTpl('tabs', [
|
||||
{
|
||||
title: '属性',
|
||||
body: getSchemaTpl('collapseGroup', [
|
||||
{
|
||||
title: '基本',
|
||||
body: [
|
||||
getSchemaTpl('formItemName', {
|
||||
required: true
|
||||
}),
|
||||
getSchemaTpl('label'),
|
||||
getSchemaTpl('selectDateRangeType', {
|
||||
value: this.scaffold.type,
|
||||
onChange: (
|
||||
value: string,
|
||||
oldValue: any,
|
||||
model: any,
|
||||
form: any
|
||||
) => {
|
||||
const type: string = value.split('-')[1];
|
||||
form.setValues({
|
||||
inputFormat: DateType[type]?.format,
|
||||
placeholder: DateType[type]?.placeholder,
|
||||
format: type === 'time' ? 'HH:mm' : 'X',
|
||||
minDate: '',
|
||||
maxDate: '',
|
||||
value: '',
|
||||
ranges: DateType[type]?.ranges
|
||||
});
|
||||
}
|
||||
}),
|
||||
{
|
||||
type: 'input-text',
|
||||
name: 'format',
|
||||
label: tipedLabel(
|
||||
'值格式',
|
||||
'提交数据前将根据设定格式化数据,请参考 <a href="https://momentjs.com/" target="_blank">moment</a> 中的格式用法。'
|
||||
),
|
||||
pipeIn: defaultValue('X')
|
||||
},
|
||||
{
|
||||
type: 'input-text',
|
||||
name: 'inputFormat',
|
||||
label: tipedLabel(
|
||||
'显示格式',
|
||||
'请参考 <a href="https://momentjs.com/" target="_blank">moment</a> 中的格式用法。'
|
||||
),
|
||||
pipeIn: defaultValue('YYYY-MM-DD'),
|
||||
clearable: true
|
||||
// onChange: (
|
||||
// value: string,
|
||||
// oldValue: any,
|
||||
// model: any,
|
||||
// form: any
|
||||
// ) => {
|
||||
// model.setOptions(
|
||||
// DateType[form.data.type.split('-')[1]].formatOptions
|
||||
// );
|
||||
// },
|
||||
// options:
|
||||
// DateType[this.scaffold.type.split('-')[1]].formatOptions
|
||||
},
|
||||
getSchemaTpl('utc'),
|
||||
getSchemaTpl('clearable', {
|
||||
pipeIn: defaultValue(true)
|
||||
}),
|
||||
body: getSchemaTpl(
|
||||
'collapseGroup',
|
||||
[
|
||||
{
|
||||
title: '基本',
|
||||
body: [
|
||||
getSchemaTpl('formItemName', {
|
||||
required: true
|
||||
}),
|
||||
getSchemaTpl('label'),
|
||||
getSchemaTpl('selectDateRangeType', {
|
||||
value: this.scaffold.type,
|
||||
onChange: (
|
||||
value: string,
|
||||
oldValue: any,
|
||||
model: any,
|
||||
form: any
|
||||
) => {
|
||||
const type: string = value.split('-')[1];
|
||||
form.setValues({
|
||||
inputFormat: DateType[type]?.format,
|
||||
placeholder: DateType[type]?.placeholder,
|
||||
format: type === 'time' ? 'HH:mm' : 'X',
|
||||
minDate: '',
|
||||
maxDate: '',
|
||||
value: '',
|
||||
ranges: DateType[type]?.ranges
|
||||
});
|
||||
}
|
||||
}),
|
||||
{
|
||||
type: 'input-text',
|
||||
name: 'format',
|
||||
label: tipedLabel(
|
||||
'值格式',
|
||||
'提交数据前将根据设定格式化数据,请参考 <a href="https://momentjs.com/" target="_blank">moment</a> 中的格式用法。'
|
||||
),
|
||||
pipeIn: defaultValue('X')
|
||||
},
|
||||
{
|
||||
type: 'input-text',
|
||||
name: 'inputFormat',
|
||||
label: tipedLabel(
|
||||
'显示格式',
|
||||
'请参考 <a href="https://momentjs.com/" target="_blank">moment</a> 中的格式用法。'
|
||||
),
|
||||
pipeIn: defaultValue('YYYY-MM-DD'),
|
||||
clearable: true
|
||||
// onChange: (
|
||||
// value: string,
|
||||
// oldValue: any,
|
||||
// model: any,
|
||||
// form: any
|
||||
// ) => {
|
||||
// model.setOptions(
|
||||
// DateType[form.data.type.split('-')[1]].formatOptions
|
||||
// );
|
||||
// },
|
||||
// options:
|
||||
// DateType[this.scaffold.type.split('-')[1]].formatOptions
|
||||
},
|
||||
getSchemaTpl('utc'),
|
||||
getSchemaTpl('clearable', {
|
||||
pipeIn: defaultValue(true)
|
||||
}),
|
||||
|
||||
getSchemaTpl('valueFormula', {
|
||||
/* 备注: 待 amis 日期组件优化
|
||||
getSchemaTpl('valueFormula', {
|
||||
/* 备注: 待 amis 日期组件优化
|
||||
rendererSchema: {
|
||||
...context?.schema,
|
||||
size: 'full', // 备注:目前样式还有问题,需要在amis端进行优化
|
||||
@ -257,120 +255,127 @@ export class DateRangeControlPlugin extends BasePlugin {
|
||||
},
|
||||
mode: 'vertical',
|
||||
*/
|
||||
rendererSchema: {
|
||||
type: 'input-date'
|
||||
},
|
||||
label: tipedLabel(
|
||||
'默认值',
|
||||
'支持 <code>now、+1day、-2weeks、+1hours、+2years</code>等这种相对值用法'
|
||||
)
|
||||
}),
|
||||
getSchemaTpl('valueFormula', {
|
||||
name: 'minDate',
|
||||
rendererSchema: {
|
||||
...context?.schema,
|
||||
value: context?.schema.minDate,
|
||||
type: 'input-date'
|
||||
},
|
||||
needDeleteProps: ['minDate'], // 避免自我限制
|
||||
label: tipedLabel('最小值', tipedLabelText)
|
||||
}),
|
||||
getSchemaTpl('valueFormula', {
|
||||
name: 'maxDate',
|
||||
rendererSchema: {
|
||||
...context?.schema,
|
||||
value: context?.schema.maxDate,
|
||||
type: 'input-date'
|
||||
},
|
||||
needDeleteProps: ['maxDate'], // 避免自我限制
|
||||
label: tipedLabel('最大值', tipedLabelText)
|
||||
}),
|
||||
rendererSchema: {
|
||||
type: 'input-date'
|
||||
},
|
||||
label: tipedLabel(
|
||||
'默认值',
|
||||
'支持 <code>now、+1day、-2weeks、+1hours、+2years</code>等这种相对值用法'
|
||||
)
|
||||
}),
|
||||
getSchemaTpl('valueFormula', {
|
||||
name: 'minDate',
|
||||
rendererSchema: {
|
||||
...context?.schema,
|
||||
value: context?.schema.minDate,
|
||||
type: 'input-date'
|
||||
},
|
||||
needDeleteProps: ['minDate'], // 避免自我限制
|
||||
label: tipedLabel('最小值', tipedLabelText)
|
||||
}),
|
||||
getSchemaTpl('valueFormula', {
|
||||
name: 'maxDate',
|
||||
rendererSchema: {
|
||||
...context?.schema,
|
||||
value: context?.schema.maxDate,
|
||||
type: 'input-date'
|
||||
},
|
||||
needDeleteProps: ['maxDate'], // 避免自我限制
|
||||
label: tipedLabel('最大值', tipedLabelText)
|
||||
}),
|
||||
|
||||
getSchemaTpl('formulaControl', {
|
||||
name: 'minDuration',
|
||||
label: tipedLabel('最小跨度', '例如 2days'),
|
||||
placeholder: '请输入最小跨度',
|
||||
inputClassName: 'is-inline'
|
||||
}),
|
||||
getSchemaTpl('formulaControl', {
|
||||
name: 'maxDuration',
|
||||
label: tipedLabel('最大跨度', '例如 1year'),
|
||||
placeholder: '请输入最大跨度',
|
||||
inputClassName: 'is-inline'
|
||||
}),
|
||||
getSchemaTpl('dateShortCutControl', {
|
||||
mode: 'normal',
|
||||
dropDownOption: {
|
||||
'yesterday': '昨天',
|
||||
'thisweek': '这个周',
|
||||
'prevweek': '上周',
|
||||
'7daysago': '最近7天',
|
||||
'thismonth': '这个月',
|
||||
'prevmonth': '上个月',
|
||||
'thisquarter': '这个季度',
|
||||
'prevquarter': '上个季度',
|
||||
'thisyear': '今年'
|
||||
}
|
||||
}),
|
||||
// getSchemaTpl('remark'),
|
||||
// getSchemaTpl('labelRemark'),
|
||||
{
|
||||
type: 'input-text',
|
||||
name: 'startPlaceholder',
|
||||
label: '前占位提示',
|
||||
pipeIn: defaultValue('开始时间')
|
||||
},
|
||||
{
|
||||
type: 'input-text',
|
||||
name: 'endPlaceholder',
|
||||
label: '后占位提示',
|
||||
pipeIn: defaultValue('结束时间')
|
||||
}
|
||||
]
|
||||
},
|
||||
getSchemaTpl('status', {isFormItem: true}),
|
||||
getSchemaTpl('validation', {
|
||||
tag: ValidatorTag.Date
|
||||
})
|
||||
], {...context?.schema, configTitle: 'props'})
|
||||
getSchemaTpl('formulaControl', {
|
||||
name: 'minDuration',
|
||||
label: tipedLabel('最小跨度', '例如 2days'),
|
||||
placeholder: '请输入最小跨度',
|
||||
inputClassName: 'is-inline'
|
||||
}),
|
||||
getSchemaTpl('formulaControl', {
|
||||
name: 'maxDuration',
|
||||
label: tipedLabel('最大跨度', '例如 1year'),
|
||||
placeholder: '请输入最大跨度',
|
||||
inputClassName: 'is-inline'
|
||||
}),
|
||||
getSchemaTpl('dateShortCutControl', {
|
||||
mode: 'normal',
|
||||
dropDownOption: {
|
||||
'yesterday': '昨天',
|
||||
'thisweek': '这个周',
|
||||
'prevweek': '上周',
|
||||
'7daysago': '最近7天',
|
||||
'thismonth': '这个月',
|
||||
'prevmonth': '上个月',
|
||||
'thisquarter': '这个季度',
|
||||
'prevquarter': '上个季度',
|
||||
'thisyear': '今年'
|
||||
}
|
||||
}),
|
||||
// getSchemaTpl('remark'),
|
||||
// getSchemaTpl('labelRemark'),
|
||||
{
|
||||
type: 'input-text',
|
||||
name: 'startPlaceholder',
|
||||
label: '前占位提示',
|
||||
pipeIn: defaultValue('开始时间')
|
||||
},
|
||||
{
|
||||
type: 'input-text',
|
||||
name: 'endPlaceholder',
|
||||
label: '后占位提示',
|
||||
pipeIn: defaultValue('选择结束时间')
|
||||
},
|
||||
getSchemaTpl('autoFillApi')
|
||||
]
|
||||
},
|
||||
getSchemaTpl('status', {isFormItem: true}),
|
||||
getSchemaTpl('validation', {
|
||||
tag: ValidatorTag.Date
|
||||
})
|
||||
],
|
||||
{...context?.schema, configTitle: 'props'}
|
||||
)
|
||||
},
|
||||
{
|
||||
title: '外观',
|
||||
body: getSchemaTpl('collapseGroup', [
|
||||
getSchemaTpl('style:formItem', renderer),
|
||||
getSchemaTpl('style:classNames', [
|
||||
getSchemaTpl('className', {
|
||||
label: '描述',
|
||||
name: 'descriptionClassName',
|
||||
visibleOn: 'this.description'
|
||||
}),
|
||||
getSchemaTpl('className', {
|
||||
name: 'addOn.className',
|
||||
label: 'AddOn',
|
||||
visibleOn: 'this.addOn && this.addOn.type === "text"'
|
||||
})
|
||||
]),
|
||||
getSchemaTpl('style:others', [
|
||||
{
|
||||
name: 'embed',
|
||||
type: 'button-group-select',
|
||||
size: 'md',
|
||||
label: '模式',
|
||||
mode: 'row',
|
||||
value: false,
|
||||
options: [
|
||||
{
|
||||
label: '浮层',
|
||||
value: false
|
||||
},
|
||||
{
|
||||
label: '内嵌',
|
||||
value: true
|
||||
}
|
||||
]
|
||||
}
|
||||
])
|
||||
], {...context?.schema, configTitle: 'style'})
|
||||
body: getSchemaTpl(
|
||||
'collapseGroup',
|
||||
[
|
||||
getSchemaTpl('style:formItem', renderer),
|
||||
getSchemaTpl('style:classNames', [
|
||||
getSchemaTpl('className', {
|
||||
label: '描述',
|
||||
name: 'descriptionClassName',
|
||||
visibleOn: 'this.description'
|
||||
}),
|
||||
getSchemaTpl('className', {
|
||||
name: 'addOn.className',
|
||||
label: 'AddOn',
|
||||
visibleOn: 'this.addOn && this.addOn.type === "text"'
|
||||
})
|
||||
]),
|
||||
getSchemaTpl('style:others', [
|
||||
{
|
||||
name: 'embed',
|
||||
type: 'button-group-select',
|
||||
size: 'md',
|
||||
label: '模式',
|
||||
mode: 'row',
|
||||
value: false,
|
||||
options: [
|
||||
{
|
||||
label: '浮层',
|
||||
value: false
|
||||
},
|
||||
{
|
||||
label: '内嵌',
|
||||
value: true
|
||||
}
|
||||
]
|
||||
}
|
||||
])
|
||||
],
|
||||
{...context?.schema, configTitle: 'style'}
|
||||
)
|
||||
},
|
||||
{
|
||||
title: '事件',
|
||||
|
@ -1,13 +1,9 @@
|
||||
import {defaultValue, getSchemaTpl, valuePipeOut} from 'amis-editor-core';
|
||||
import {registerEditorPlugin} from 'amis-editor-core';
|
||||
import {registerEditorPlugin, tipedLabel} from 'amis-editor-core';
|
||||
import {BasePlugin, BaseEventContext} from 'amis-editor-core';
|
||||
import {tipedLabel} from '../../component/BaseControl';
|
||||
import {ValidatorTag} from '../../validator';
|
||||
import {getEventControlConfig} from '../../util';
|
||||
import {
|
||||
RendererPluginAction,
|
||||
RendererPluginEvent
|
||||
} from 'amis-editor-core';
|
||||
import {RendererPluginAction, RendererPluginEvent} from 'amis-editor-core';
|
||||
|
||||
export class FileControlPlugin extends BasePlugin {
|
||||
// 关联渲染器名字
|
||||
@ -348,7 +344,8 @@ export class FileControlPlugin extends BasePlugin {
|
||||
}),
|
||||
getSchemaTpl('remark'),
|
||||
getSchemaTpl('labelRemark'),
|
||||
getSchemaTpl('description')
|
||||
getSchemaTpl('description'),
|
||||
getSchemaTpl('autoFillApi')
|
||||
// getSchemaTpl('autoFill')
|
||||
]
|
||||
},
|
||||
|
@ -2,10 +2,8 @@ import {getSchemaTpl, valuePipeOut} from 'amis-editor-core';
|
||||
import {registerEditorPlugin} from 'amis-editor-core';
|
||||
import {BasePlugin, BaseEventContext} from 'amis-editor-core';
|
||||
import {formItemControl} from '../../component/BaseControl';
|
||||
import {
|
||||
RendererPluginAction,
|
||||
RendererPluginEvent
|
||||
} from 'amis-editor-core';
|
||||
import {RendererPluginAction, RendererPluginEvent} from 'amis-editor-core';
|
||||
|
||||
export class ImageControlPlugin extends BasePlugin {
|
||||
// 关联渲染器名字
|
||||
rendererName = 'input-image';
|
||||
|
@ -1,7 +1,4 @@
|
||||
import {
|
||||
RendererPluginAction,
|
||||
RendererPluginEvent
|
||||
} from 'amis-editor-core';
|
||||
import {RendererPluginAction, RendererPluginEvent} from 'amis-editor-core';
|
||||
import flatten from 'lodash/flatten';
|
||||
import {ContainerWrapper} from 'amis-editor-core';
|
||||
import {registerEditorPlugin} from 'amis-editor-core';
|
||||
@ -13,8 +10,7 @@ import {
|
||||
SubRendererInfo,
|
||||
BaseEventContext
|
||||
} from 'amis-editor-core';
|
||||
import {defaultValue, getSchemaTpl} from 'amis-editor-core';
|
||||
import {tipedLabel} from '../../component/BaseControl';
|
||||
import {defaultValue, getSchemaTpl, tipedLabel} from 'amis-editor-core';
|
||||
import {ValidatorTag} from '../../validator';
|
||||
import {getEventControlConfig} from '../../util';
|
||||
|
||||
|
@ -1,11 +1,7 @@
|
||||
import {
|
||||
RendererPluginAction,
|
||||
RendererPluginEvent
|
||||
} from 'amis-editor-core';
|
||||
import {defaultValue, getSchemaTpl} from 'amis-editor-core';
|
||||
import {RendererPluginAction, RendererPluginEvent} from 'amis-editor-core';
|
||||
import {defaultValue, getSchemaTpl, tipedLabel} from 'amis-editor-core';
|
||||
import {registerEditorPlugin} from 'amis-editor-core';
|
||||
import {BasePlugin, BaseEventContext} from 'amis-editor-core';
|
||||
import {tipedLabel} from '../../component/BaseControl';
|
||||
import {ValidatorTag} from '../../validator';
|
||||
import {getEventControlConfig} from '../../util';
|
||||
|
||||
@ -278,7 +274,8 @@ export class RangeControlPlugin extends BasePlugin {
|
||||
label: '可重置',
|
||||
value: false,
|
||||
visibleOn: '!!data.showInput'
|
||||
})
|
||||
}),
|
||||
getSchemaTpl('autoFillApi')
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -5,14 +5,10 @@ import {
|
||||
undefinedPipeOut
|
||||
} from 'amis-editor-core';
|
||||
import {registerEditorPlugin} from 'amis-editor-core';
|
||||
import {BasePlugin, BaseEventContext} from 'amis-editor-core';
|
||||
import {tipedLabel} from '../../component/BaseControl';
|
||||
import {BasePlugin, BaseEventContext, tipedLabel} from 'amis-editor-core';
|
||||
import {ValidatorTag} from '../../validator';
|
||||
import {getEventControlConfig} from '../../util';
|
||||
import {
|
||||
RendererPluginAction,
|
||||
RendererPluginEvent
|
||||
} from 'amis-editor-core';
|
||||
import {RendererPluginAction, RendererPluginEvent} from 'amis-editor-core';
|
||||
|
||||
export class RateControlPlugin extends BasePlugin {
|
||||
// 关联渲染器名字
|
||||
@ -234,7 +230,8 @@ export class RateControlPlugin extends BasePlugin {
|
||||
|
||||
return res;
|
||||
}
|
||||
})
|
||||
}),
|
||||
getSchemaTpl('autoFillApi')
|
||||
]
|
||||
},
|
||||
getSchemaTpl('status', {isFormItem: true, readonly: true}),
|
||||
|
@ -1,4 +1,5 @@
|
||||
import {Button} from 'amis';
|
||||
import { SchemaCollection } from 'amis/lib/Schema';
|
||||
import React from 'react';
|
||||
import {registerEditorPlugin} from 'amis-editor-core';
|
||||
import {
|
||||
@ -94,7 +95,7 @@ export class SubFormControlPlugin extends BasePlugin {
|
||||
label: '允许最多个数',
|
||||
type: 'input-number'
|
||||
}
|
||||
];
|
||||
] as SchemaCollection;
|
||||
};
|
||||
|
||||
filterProps(props: any) {
|
||||
|
@ -9,10 +9,7 @@ import {
|
||||
} from 'amis-editor-core';
|
||||
|
||||
import {formItemControl} from '../../component/BaseControl';
|
||||
import {
|
||||
RendererPluginAction,
|
||||
RendererPluginEvent
|
||||
} from 'amis-editor-core';
|
||||
import {RendererPluginAction, RendererPluginEvent} from 'amis-editor-core';
|
||||
|
||||
export class TagControlPlugin extends BasePlugin {
|
||||
// 关联渲染器名字
|
||||
|
@ -6,8 +6,7 @@ import {
|
||||
SubRendererInfo,
|
||||
BaseEventContext
|
||||
} from 'amis-editor-core';
|
||||
import {defaultValue, getSchemaTpl, setSchemaTpl} from 'amis-editor-core';
|
||||
import {tipedLabel} from '../../component/BaseControl';
|
||||
import {defaultValue, getSchemaTpl, tipedLabel} from 'amis-editor-core';
|
||||
import {ValidatorTag} from '../../validator';
|
||||
import {getEventControlConfig} from '../../util';
|
||||
|
||||
@ -222,7 +221,7 @@ export class TextControlPlugin extends BasePlugin {
|
||||
{
|
||||
name: 'addOn',
|
||||
label: tipedLabel('AddOn', '输入框左侧或右侧的附加挂件'),
|
||||
type: 'ae-Switch-More',
|
||||
type: 'ae-switch-more',
|
||||
mode: 'normal',
|
||||
formType: 'extend',
|
||||
title: 'AddOn',
|
||||
|
@ -1,13 +1,10 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
RendererPluginAction,
|
||||
RendererPluginEvent
|
||||
} from 'amis-editor-core';
|
||||
import {RendererPluginAction, RendererPluginEvent} from 'amis-editor-core';
|
||||
import {defaultValue, getSchemaTpl} from 'amis-editor-core';
|
||||
import {registerEditorPlugin} from 'amis-editor-core';
|
||||
import {BaseEventContext, BasePlugin} from 'amis-editor-core';
|
||||
import {getEventControlConfig} from '../../util';
|
||||
import { getArgsWrapper } from '../../renderer/event-control/helper';
|
||||
import {getArgsWrapper} from '../../renderer/event-control/helper';
|
||||
|
||||
export class TreeControlPlugin extends BasePlugin {
|
||||
// 关联渲染器名字
|
||||
|
@ -112,9 +112,15 @@ export class ItemPlugin extends BasePlugin {
|
||||
ignoreValidator ? null : getSchemaTpl('required'),
|
||||
getSchemaTpl('description'),
|
||||
getSchemaTpl('placeholder'),
|
||||
getSchemaTpl('remark'),
|
||||
renderer.renderLabel !== false ? getSchemaTpl('labelRemark') : null,
|
||||
autoFillApi ? getSchemaTpl('autoFillApi') : null
|
||||
getSchemaTpl('remark', {
|
||||
mode: 'row'
|
||||
}),
|
||||
renderer.renderLabel !== false
|
||||
? getSchemaTpl('labelRemark', {
|
||||
mode: 'row'
|
||||
})
|
||||
: null,
|
||||
getSchemaTpl('autoFillApi')
|
||||
]
|
||||
},
|
||||
|
||||
|
@ -111,6 +111,8 @@ export class ListControlPlugin extends BasePlugin {
|
||||
}),
|
||||
getSchemaTpl('label'),
|
||||
getSchemaTpl('multiple'),
|
||||
getSchemaTpl('extractValue'),
|
||||
|
||||
getSchemaTpl('valueFormula', {
|
||||
rendererSchema: context?.schema,
|
||||
useSelectMode: true, // 改用 Select 设置模式
|
||||
|
@ -5,15 +5,12 @@ import {
|
||||
BasicSubRenderInfo,
|
||||
RendererEventContext,
|
||||
SubRendererInfo,
|
||||
BaseEventContext
|
||||
BaseEventContext,
|
||||
tipedLabel
|
||||
} from 'amis-editor-core';
|
||||
import {tipedLabel} from '../../component/BaseControl';
|
||||
import {ValidatorTag} from '../../validator';
|
||||
import {getEventControlConfig} from '../../util';
|
||||
import {
|
||||
RendererPluginAction,
|
||||
RendererPluginEvent
|
||||
} from 'amis-editor-core';
|
||||
import {RendererPluginAction, RendererPluginEvent} from 'amis-editor-core';
|
||||
|
||||
export class MatrixControlPlugin extends BasePlugin {
|
||||
// 关联渲染器名字
|
||||
@ -151,7 +148,8 @@ export class MatrixControlPlugin extends BasePlugin {
|
||||
}
|
||||
],
|
||||
pipeIn: defaultValue('column')
|
||||
}
|
||||
},
|
||||
getSchemaTpl('autoFillApi')
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -1,8 +1,5 @@
|
||||
import {relativeValueRe} from 'amis';
|
||||
import {
|
||||
RendererPluginAction,
|
||||
RendererPluginEvent
|
||||
} from 'amis-editor-core';
|
||||
import {RendererPluginAction, RendererPluginEvent} from 'amis-editor-core';
|
||||
import {availableLanguages} from 'amis/lib/renderers/Form/Editor';
|
||||
import {defaultValue, getSchemaTpl, valuePipeOut} from 'amis-editor-core';
|
||||
import {registerEditorPlugin} from 'amis-editor-core';
|
||||
@ -11,9 +8,9 @@ import {
|
||||
BasicSubRenderInfo,
|
||||
RendererEventContext,
|
||||
SubRendererInfo,
|
||||
BaseEventContext
|
||||
BaseEventContext,
|
||||
tipedLabel
|
||||
} from 'amis-editor-core';
|
||||
import {tipedLabel} from '../../component/BaseControl';
|
||||
import {ValidatorTag} from '../../validator';
|
||||
import {getEventControlConfig} from '../../util';
|
||||
|
||||
@ -285,7 +282,8 @@ export class NestedSelectControlPlugin extends BasePlugin {
|
||||
getSchemaTpl('labelRemark'),
|
||||
getSchemaTpl('remark'),
|
||||
getSchemaTpl('placeholder'),
|
||||
getSchemaTpl('description')
|
||||
getSchemaTpl('description'),
|
||||
getSchemaTpl('autoFillApi')
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -4,10 +4,7 @@ import {BasePlugin, BaseEventContext} from 'amis-editor-core';
|
||||
|
||||
import {ValidatorTag} from '../../validator';
|
||||
import {getEventControlConfig} from '../../util';
|
||||
import {
|
||||
RendererPluginAction,
|
||||
RendererPluginEvent
|
||||
} from 'amis-editor-core';
|
||||
import {RendererPluginAction, RendererPluginEvent} from 'amis-editor-core';
|
||||
|
||||
export class RadiosControlPlugin extends BasePlugin {
|
||||
// 关联渲染器名字
|
||||
@ -122,7 +119,8 @@ export class RadiosControlPlugin extends BasePlugin {
|
||||
}),
|
||||
// getSchemaTpl('autoFill')
|
||||
getSchemaTpl('labelRemark'),
|
||||
getSchemaTpl('remark')
|
||||
getSchemaTpl('remark'),
|
||||
getSchemaTpl('autoFillApi')
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -1,15 +1,10 @@
|
||||
import {getSchemaTpl} from 'amis-editor-core';
|
||||
import {registerEditorPlugin} from 'amis-editor-core';
|
||||
import {BasePlugin, BaseEventContext} from 'amis-editor-core';
|
||||
import isArray from 'lodash/isArray';
|
||||
|
||||
import {tipedLabel} from '../../component/BaseControl';
|
||||
import {ValidatorTag} from '../../validator';
|
||||
import {getEventControlConfig} from '../../util';
|
||||
import {
|
||||
RendererPluginAction,
|
||||
RendererPluginEvent
|
||||
} from 'amis-editor-core';
|
||||
import {RendererPluginAction, RendererPluginEvent} from 'amis-editor-core';
|
||||
|
||||
export class SelectControlPlugin extends BasePlugin {
|
||||
// 关联渲染器名字
|
||||
@ -225,7 +220,8 @@ export class SelectControlPlugin extends BasePlugin {
|
||||
getSchemaTpl('labelRemark'),
|
||||
getSchemaTpl('remark'),
|
||||
getSchemaTpl('placeholder'),
|
||||
getSchemaTpl('description')
|
||||
getSchemaTpl('description'),
|
||||
getSchemaTpl('autoFillApi')
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -263,7 +259,7 @@ export class SelectControlPlugin extends BasePlugin {
|
||||
}
|
||||
}),
|
||||
getSchemaTpl('editable', {
|
||||
type: 'ae-Switch-More',
|
||||
type: 'ae-switch-more',
|
||||
formType: 'extend',
|
||||
hiddenOnDefault: true,
|
||||
form: {
|
||||
@ -271,7 +267,7 @@ export class SelectControlPlugin extends BasePlugin {
|
||||
}
|
||||
}),
|
||||
getSchemaTpl('removable', {
|
||||
type: 'ae-Switch-More',
|
||||
type: 'ae-switch-more',
|
||||
formType: 'extend',
|
||||
hiddenOnDefault: true,
|
||||
form: {
|
||||
|
@ -4,10 +4,7 @@ import {defaultValue, getSchemaTpl} from 'amis-editor-core';
|
||||
import {registerEditorPlugin} from 'amis-editor-core';
|
||||
import {BaseEventContext, BasePlugin} from 'amis-editor-core';
|
||||
import {EditorNodeType} from 'amis-editor-core';
|
||||
import {mockValue} from 'amis-editor-core';
|
||||
import {tipedLabel} from '../../component/BaseControl';
|
||||
import {ValidatorTag} from '../../validator';
|
||||
import {getEventControlConfig} from '../../util';
|
||||
import {mockValue, tipedLabel} from 'amis-editor-core';
|
||||
|
||||
export class StaticControlPlugin extends BasePlugin {
|
||||
// 关联渲染器名字
|
||||
@ -64,7 +61,7 @@ export class StaticControlPlugin extends BasePlugin {
|
||||
rendererSchema: {
|
||||
...context?.schema,
|
||||
type: 'textarea', // 改用多行文本编辑
|
||||
value: context?.schema.tpl, // 避免默认值丢失
|
||||
value: context?.schema.tpl // 避免默认值丢失
|
||||
},
|
||||
mode: 'vertical', // 改成上下展示模式
|
||||
name: 'tpl'
|
||||
@ -294,7 +291,8 @@ export class StaticControlPlugin extends BasePlugin {
|
||||
getSchemaTpl('labelRemark'),
|
||||
getSchemaTpl('remark'),
|
||||
getSchemaTpl('placeholder'),
|
||||
getSchemaTpl('description')
|
||||
getSchemaTpl('description'),
|
||||
getSchemaTpl('autoFillApi')
|
||||
/*{
|
||||
children: (
|
||||
<Button
|
||||
|
@ -1,13 +1,9 @@
|
||||
import {getSchemaTpl, valuePipeOut} from 'amis-editor-core';
|
||||
import {registerEditorPlugin} from 'amis-editor-core';
|
||||
import {registerEditorPlugin, tipedLabel} from 'amis-editor-core';
|
||||
import {BasePlugin, BaseEventContext} from 'amis-editor-core';
|
||||
import {tipedLabel} from '../../component/BaseControl';
|
||||
import {ValidatorTag} from '../../validator';
|
||||
import {getEventControlConfig} from '../../util';
|
||||
import type {
|
||||
RendererPluginAction,
|
||||
RendererPluginEvent
|
||||
} from 'amis-editor-core';
|
||||
import type {RendererPluginAction, RendererPluginEvent} from 'amis-editor-core';
|
||||
|
||||
export class SwitchControlPlugin extends BasePlugin {
|
||||
// 关联渲染器名字
|
||||
@ -97,7 +93,7 @@ export class SwitchControlPlugin extends BasePlugin {
|
||||
},
|
||||
|
||||
{
|
||||
type: 'ae-Switch-More',
|
||||
type: 'ae-switch-more',
|
||||
bulk: true,
|
||||
mode: 'normal',
|
||||
label: '填充文本',
|
||||
@ -120,7 +116,7 @@ export class SwitchControlPlugin extends BasePlugin {
|
||||
},
|
||||
|
||||
{
|
||||
type: 'ae-Switch-More',
|
||||
type: 'ae-switch-more',
|
||||
bulk: true,
|
||||
mode: 'normal',
|
||||
label: tipedLabel(
|
||||
@ -199,7 +195,8 @@ export class SwitchControlPlugin extends BasePlugin {
|
||||
}),
|
||||
getSchemaTpl('labelRemark'),
|
||||
getSchemaTpl('remark'),
|
||||
getSchemaTpl('description')
|
||||
getSchemaTpl('description'),
|
||||
getSchemaTpl('autoFillApi')
|
||||
]
|
||||
},
|
||||
getSchemaTpl('status', {isFormItem: true}),
|
||||
|
@ -1,15 +1,11 @@
|
||||
import {defaultValue, getSchemaTpl} from 'amis-editor-core';
|
||||
import {registerEditorPlugin} from 'amis-editor-core';
|
||||
import {BasePlugin} from 'amis-editor-core';
|
||||
import {BasePlugin, tipedLabel} from 'amis-editor-core';
|
||||
|
||||
import type {BaseEventContext} from 'amis-editor-core';
|
||||
import {tipedLabel} from '../../component/BaseControl';
|
||||
import {ValidatorTag} from '../../validator';
|
||||
import {getEventControlConfig} from '../../util';
|
||||
import {
|
||||
RendererPluginAction,
|
||||
RendererPluginEvent
|
||||
} from 'amis-editor-core';
|
||||
import {RendererPluginAction, RendererPluginEvent} from 'amis-editor-core';
|
||||
|
||||
export class TextareaControlPlugin extends BasePlugin {
|
||||
// 关联渲染器名字
|
||||
@ -142,7 +138,8 @@ export class TextareaControlPlugin extends BasePlugin {
|
||||
getSchemaTpl('labelRemark'),
|
||||
getSchemaTpl('remark'),
|
||||
getSchemaTpl('placeholder'),
|
||||
getSchemaTpl('description')
|
||||
getSchemaTpl('description'),
|
||||
getSchemaTpl('autoFillApi')
|
||||
]
|
||||
},
|
||||
getSchemaTpl('status', {
|
||||
|
@ -3,10 +3,10 @@ import {
|
||||
BasePlugin,
|
||||
RegionConfig,
|
||||
RendererInfo,
|
||||
BaseEventContext
|
||||
BaseEventContext,
|
||||
tipedLabel
|
||||
} from 'amis-editor-core';
|
||||
import {defaultValue, getSchemaTpl, valuePipeOut} from 'amis-editor-core';
|
||||
import {formItemControl, tipedLabel} from '../component/BaseControl';
|
||||
|
||||
export class IFramePlugin extends BasePlugin {
|
||||
// 关联渲染器名字
|
||||
|
@ -1,13 +1,10 @@
|
||||
import {registerEditorPlugin} from 'amis-editor-core';
|
||||
import {BasePlugin, RegionConfig, RendererInfo} from 'amis-editor-core';
|
||||
import {defaultValue, getSchemaTpl} from 'amis-editor-core';
|
||||
import {tipedLabel} from '../component/BaseControl';
|
||||
import {tipedLabel} from 'amis-editor-core';
|
||||
import {ValidatorTag} from '../validator';
|
||||
import {getEventControlConfig} from '../util';
|
||||
import {
|
||||
RendererPluginAction,
|
||||
RendererPluginEvent
|
||||
} from 'amis-editor-core';
|
||||
import {RendererPluginAction, RendererPluginEvent} from 'amis-editor-core';
|
||||
|
||||
export class LinkPlugin extends BasePlugin {
|
||||
// 关联渲染器名字
|
||||
|
@ -13,6 +13,8 @@ import {
|
||||
} from 'amis-editor-core';
|
||||
import {defaultValue, getSchemaTpl} from 'amis-editor-core';
|
||||
import {diff, JSONPipeOut, repeatArray} from 'amis-editor-core';
|
||||
import {getEventControlConfig} from '../util';
|
||||
import {ListItemSchema} from 'amis/lib/renderers/List';
|
||||
|
||||
export class ListPlugin extends BasePlugin {
|
||||
// 关联渲染器名字
|
||||
@ -55,118 +57,148 @@ export class ListPlugin extends BasePlugin {
|
||||
};
|
||||
|
||||
panelTitle = '列表';
|
||||
panelJustify = true;
|
||||
panelBodyCreator = (context: BaseEventContext) => {
|
||||
const isCRUDBody = context.schema.type === 'crud';
|
||||
const isCRUDBody = ['crud', 'crud2'].includes(context.schema.type);
|
||||
|
||||
return getSchemaTpl('tabs', [
|
||||
{
|
||||
title: '常规',
|
||||
body: [
|
||||
title: '属性',
|
||||
body: getSchemaTpl('collapseGroup', [
|
||||
{
|
||||
children: (
|
||||
<Button
|
||||
level="danger"
|
||||
size="sm"
|
||||
block
|
||||
onClick={this.editDetail.bind(this, context.id)}
|
||||
>
|
||||
配置成员详情
|
||||
</Button>
|
||||
)
|
||||
},
|
||||
{
|
||||
type: 'divider'
|
||||
},
|
||||
{
|
||||
name: 'title',
|
||||
type: 'input-text',
|
||||
label: '标题'
|
||||
},
|
||||
isCRUDBody
|
||||
? null
|
||||
: {
|
||||
name: 'source',
|
||||
title: '基本',
|
||||
body: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'input-text',
|
||||
label: '数据源',
|
||||
pipeIn: defaultValue('${items}'),
|
||||
description: '绑定当前环境变量'
|
||||
label: '标题'
|
||||
},
|
||||
{
|
||||
name: 'placeholder',
|
||||
pipeIn: defaultValue('没有数据'),
|
||||
type: 'input-text',
|
||||
label: '无数据提示'
|
||||
}
|
||||
]
|
||||
isCRUDBody
|
||||
? null
|
||||
: {
|
||||
name: 'source',
|
||||
type: 'input-text',
|
||||
label: '数据源',
|
||||
pipeIn: defaultValue('${items}'),
|
||||
description: '绑定当前环境变量'
|
||||
},
|
||||
{
|
||||
name: 'placeholder',
|
||||
pipeIn: defaultValue('没有数据'),
|
||||
type: 'input-text',
|
||||
label: '无数据提示'
|
||||
}
|
||||
]
|
||||
},
|
||||
getSchemaTpl('status', {
|
||||
isFormItem: false
|
||||
})
|
||||
])
|
||||
},
|
||||
{
|
||||
title: '外观',
|
||||
body: [
|
||||
getSchemaTpl('switch', {
|
||||
name: 'showHeader',
|
||||
label: '是否显示头部',
|
||||
pipeIn: defaultValue(true)
|
||||
}),
|
||||
body: getSchemaTpl('collapseGroup', [
|
||||
{
|
||||
title: '基本',
|
||||
body: [
|
||||
getSchemaTpl('switch', {
|
||||
name: 'showHeader',
|
||||
label: '显示头部',
|
||||
pipeIn: defaultValue(true)
|
||||
}),
|
||||
|
||||
getSchemaTpl('switch', {
|
||||
name: 'showFooter',
|
||||
label: '是否显示底部',
|
||||
pipeIn: defaultValue(true)
|
||||
}),
|
||||
|
||||
getSchemaTpl('className', {
|
||||
label: 'CSS 类名'
|
||||
}),
|
||||
getSchemaTpl('className', {
|
||||
name: 'listClassName',
|
||||
label: 'List div CSS 类名'
|
||||
}),
|
||||
getSchemaTpl('className', {
|
||||
name: 'headerClassName',
|
||||
label: '头部 CSS 类名'
|
||||
}),
|
||||
getSchemaTpl('className', {
|
||||
name: 'footerClassName',
|
||||
label: '底部 CSS 类名'
|
||||
getSchemaTpl('switch', {
|
||||
name: 'showFooter',
|
||||
label: '显示底部',
|
||||
pipeIn: defaultValue(true)
|
||||
})
|
||||
]
|
||||
},
|
||||
getSchemaTpl('style:classNames', {
|
||||
isFormItem: false,
|
||||
schema: [
|
||||
getSchemaTpl('className', {
|
||||
name: 'listClassName',
|
||||
label: '列表项'
|
||||
}),
|
||||
getSchemaTpl('className', {
|
||||
name: 'headerClassName',
|
||||
label: '头部'
|
||||
}),
|
||||
getSchemaTpl('className', {
|
||||
name: 'footerClassName',
|
||||
label: '底部'
|
||||
})
|
||||
]
|
||||
})
|
||||
]
|
||||
])
|
||||
},
|
||||
{
|
||||
title: '显隐',
|
||||
body: [getSchemaTpl('ref'), getSchemaTpl('visible')]
|
||||
title: '事件',
|
||||
className: 'p-none',
|
||||
body: [
|
||||
getSchemaTpl('eventControl', {
|
||||
name: 'onEvent',
|
||||
...getEventControlConfig(this.manager, context)
|
||||
})
|
||||
]
|
||||
}
|
||||
]);
|
||||
};
|
||||
|
||||
filterProps(props: any) {
|
||||
if (props.isSlot) {
|
||||
props.value = [props.data];
|
||||
return props;
|
||||
overrides = {
|
||||
renderListItem(
|
||||
this: any,
|
||||
index: number,
|
||||
itemTemplace: ListItemSchema | undefined,
|
||||
...rest: any[]
|
||||
) {
|
||||
return this.super(
|
||||
index,
|
||||
// 使第一个卡片元素可以选择并编辑schema
|
||||
index > 0 ? JSONPipeOut(itemTemplace) : itemTemplace,
|
||||
...rest
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
filterProps(props: any) {
|
||||
const data = {
|
||||
...props.defaultData,
|
||||
...props.data
|
||||
};
|
||||
let arr = Array.isArray(props.value)
|
||||
let value = Array.isArray(props.value)
|
||||
? props.value
|
||||
: typeof props.source === 'string'
|
||||
? resolveVariable(props.source, data)
|
||||
: resolveVariable('items', data);
|
||||
|
||||
if (!Array.isArray(arr) || !arr.length) {
|
||||
const mockedData: any = this.buildMockData();
|
||||
props.value = repeatArray(mockedData, 1).map((item, index) => ({
|
||||
...item,
|
||||
id: index + 1
|
||||
}));
|
||||
value = !Array.isArray(value) ? [] : value;
|
||||
|
||||
if (value.length < 5) {
|
||||
const mockedData = value.length
|
||||
? value[0]
|
||||
: {
|
||||
id: 666,
|
||||
title: '假数据',
|
||||
description: '假数据',
|
||||
a: '假数据',
|
||||
b: '假数据'
|
||||
};
|
||||
|
||||
value = value.concat(
|
||||
repeatArray(mockedData, 3).map((item, index) => ({
|
||||
...item,
|
||||
id: index + 1
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
const {$schema, ...rest} = props;
|
||||
value = value.slice(0, 4);
|
||||
|
||||
return {
|
||||
...JSONPipeOut(rest),
|
||||
$schema
|
||||
...props,
|
||||
value
|
||||
};
|
||||
}
|
||||
|
||||
@ -251,7 +283,7 @@ export class ListPlugin extends BasePlugin {
|
||||
const {renderer, schema} = context;
|
||||
if (
|
||||
!schema.$$id &&
|
||||
schema.$$editor?.renderer.name === 'crud' &&
|
||||
['crud', 'crud2'].includes(schema.$$editor?.renderer.name) &&
|
||||
renderer.name === 'list'
|
||||
) {
|
||||
return {
|
||||
|
@ -13,6 +13,7 @@ import {
|
||||
} from 'amis-editor-core';
|
||||
import {defaultValue, getSchemaTpl} from 'amis-editor-core';
|
||||
import {VRenderer} from 'amis-editor-core';
|
||||
import { getEventControlConfig } from '../util';
|
||||
|
||||
export class ListItemPlugin extends BasePlugin {
|
||||
// 关联渲染器名字
|
||||
@ -37,83 +38,78 @@ export class ListItemPlugin extends BasePlugin {
|
||||
];
|
||||
|
||||
panelTitle = '列表项';
|
||||
panelBody = getSchemaTpl('tabs', [
|
||||
{
|
||||
title: '基本',
|
||||
body: [
|
||||
// {
|
||||
// children: (
|
||||
// <Button
|
||||
// size="sm"
|
||||
// className="m-b-sm"
|
||||
// level="info"
|
||||
// block
|
||||
// onClick={() => {
|
||||
// this.pickChild('actions', 'actions', undefined, ['button']);
|
||||
// }}
|
||||
// >
|
||||
// 新增按钮
|
||||
// </Button>
|
||||
// )
|
||||
// },
|
||||
// {
|
||||
// children: (
|
||||
// <div>
|
||||
// <Button
|
||||
// level="primary"
|
||||
// size="sm"
|
||||
// block
|
||||
// onClick={this.handleAdd}
|
||||
// >
|
||||
// 新增内容
|
||||
// </Button>
|
||||
// </div>
|
||||
// )
|
||||
// },
|
||||
// {
|
||||
// type: 'divider'
|
||||
// },
|
||||
{
|
||||
name: 'title',
|
||||
type: 'input-text',
|
||||
label: '标题',
|
||||
descrition: '支持模板语法如: ${xxx}'
|
||||
},
|
||||
{
|
||||
name: 'subTitle',
|
||||
type: 'input-text',
|
||||
label: '副标题',
|
||||
descrition: '支持模板语法如: ${xxx}'
|
||||
},
|
||||
{
|
||||
name: 'avatar',
|
||||
type: 'input-text',
|
||||
label: '图片地址',
|
||||
descrition: '支持模板语法如: ${xxx}'
|
||||
},
|
||||
{
|
||||
name: 'desc',
|
||||
type: 'textarea',
|
||||
label: '描述',
|
||||
descrition: '支持模板语法如: ${xxx}'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '外观',
|
||||
body: [
|
||||
getSchemaTpl('className', {
|
||||
name: 'avatarClassName',
|
||||
label: '图片 CSS 类名',
|
||||
pipeIn: defaultValue('thumb-sm avatar m-r')
|
||||
}),
|
||||
getSchemaTpl('className', {
|
||||
name: 'titleClassName',
|
||||
label: '标题 CSS 类名'
|
||||
})
|
||||
]
|
||||
}
|
||||
]);
|
||||
panelJustify = true;
|
||||
panelBodyCreator = (context: BaseEventContext) => {
|
||||
const isCRUDBody = ['crud', 'crud2'].includes(context.schema.type);
|
||||
|
||||
return getSchemaTpl('tabs', [
|
||||
{
|
||||
title: '属性',
|
||||
body: getSchemaTpl('collapseGroup', [
|
||||
{
|
||||
title: '基本',
|
||||
body: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'input-text',
|
||||
label: '标题',
|
||||
descrition: '支持模板语法如: ${xxx}'
|
||||
},
|
||||
{
|
||||
name: 'subTitle',
|
||||
type: 'input-text',
|
||||
label: '副标题',
|
||||
descrition: '支持模板语法如: ${xxx}'
|
||||
},
|
||||
{
|
||||
name: 'avatar',
|
||||
type: 'input-text',
|
||||
label: '图片地址',
|
||||
descrition: '支持模板语法如: ${xxx}'
|
||||
},
|
||||
{
|
||||
name: 'desc',
|
||||
type: 'textarea',
|
||||
label: '描述',
|
||||
descrition: '支持模板语法如: ${xxx}'
|
||||
}
|
||||
]
|
||||
},
|
||||
getSchemaTpl('status', {
|
||||
isFormItem: false
|
||||
})
|
||||
])
|
||||
},
|
||||
{
|
||||
title: '外观',
|
||||
body: getSchemaTpl('collapseGroup', [
|
||||
getSchemaTpl('style:classNames', {
|
||||
isFormItem: false,
|
||||
schema: [
|
||||
getSchemaTpl('className', {
|
||||
name: 'avatarClassName',
|
||||
label: '图片'
|
||||
}),
|
||||
getSchemaTpl('className', {
|
||||
name: 'titleClassName',
|
||||
label: '标题'
|
||||
})
|
||||
]
|
||||
})
|
||||
])
|
||||
},
|
||||
{
|
||||
title: '事件',
|
||||
className: 'p-none',
|
||||
body: [
|
||||
getSchemaTpl('eventControl', {
|
||||
name: 'onEvent',
|
||||
...getEventControlConfig(this.manager, context)
|
||||
})
|
||||
]
|
||||
}
|
||||
]);
|
||||
};
|
||||
|
||||
getRendererInfo({
|
||||
renderer,
|
||||
|
@ -6,10 +6,11 @@ import {
|
||||
BasePlugin,
|
||||
BasicPanelItem,
|
||||
BasicToolbarItem,
|
||||
BuildPanelEventContext,
|
||||
BuildPanelEventContext
|
||||
} from 'amis-editor-core';
|
||||
import {defaultValue, getSchemaTpl} from 'amis-editor-core';
|
||||
import {diff} from 'amis-editor-core';
|
||||
import {SchemaCollection} from 'amis/lib/Schema';
|
||||
|
||||
export class ActionPlugin extends BasePlugin {
|
||||
panelTitle = '按钮';
|
||||
@ -350,7 +351,7 @@ export class ActionPlugin extends BasePlugin {
|
||||
className: 'p-3',
|
||||
body: schema
|
||||
}
|
||||
];
|
||||
] as SchemaCollection;
|
||||
};
|
||||
|
||||
buildEditorPanel(
|
||||
|
@ -40,11 +40,9 @@ export class TableCellPlugin extends BasePlugin {
|
||||
type: 'input-text'
|
||||
},
|
||||
|
||||
{
|
||||
name: 'name',
|
||||
type: 'input-text',
|
||||
getSchemaTpl('formItemName', {
|
||||
label: '绑定字段名'
|
||||
},
|
||||
}),
|
||||
|
||||
{
|
||||
name: 'remark',
|
||||
|
@ -177,15 +177,15 @@ export class PagePlugin extends BasePlugin {
|
||||
label: '数据初始化接口',
|
||||
name: 'initApi',
|
||||
sampleBuilder: (schema: any) => `{
|
||||
"status": 0,
|
||||
"msg": "",
|
||||
"status": 0,
|
||||
"msg": "",
|
||||
|
||||
data: {
|
||||
// 示例数据
|
||||
"id": 1,
|
||||
"a": "sample"
|
||||
}
|
||||
}`
|
||||
data: {
|
||||
// 示例数据
|
||||
"id": 1,
|
||||
"a": "sample"
|
||||
}
|
||||
}`
|
||||
}),
|
||||
|
||||
getSchemaTpl('initFetch'),
|
||||
|
@ -1,11 +1,14 @@
|
||||
import {registerEditorPlugin} from 'amis-editor-core';
|
||||
import {BasePlugin, RegionConfig, BaseEventContext} from 'amis-editor-core';
|
||||
import {tipedLabel} from '../component/BaseControl';
|
||||
import {ValidatorTag} from '../validator';
|
||||
import {getEventControlConfig} from '../util';
|
||||
import {RendererPluginEvent} from 'amis-editor-core';
|
||||
|
||||
import {defaultValue, getSchemaTpl} from 'amis-editor-core';
|
||||
import {
|
||||
getSchemaTpl,
|
||||
defaultValue,
|
||||
tipedLabel,
|
||||
BasePlugin,
|
||||
RendererPluginEvent,
|
||||
RegionConfig,
|
||||
BaseEventContext,
|
||||
registerEditorPlugin
|
||||
} from 'amis-editor-core';
|
||||
|
||||
export class PaginationPlugin extends BasePlugin {
|
||||
// 关联渲染器名字
|
||||
@ -14,17 +17,16 @@ export class PaginationPlugin extends BasePlugin {
|
||||
|
||||
// 组件名称
|
||||
name = '分页组件';
|
||||
isBaseComponent = true;
|
||||
disabledRendererPlugin = true;
|
||||
isBaseComponent = false;
|
||||
description = '分页组件,可以对列表进行分页展示,提高页面性能';
|
||||
tags = ['容器'];
|
||||
icon = 'fa fa-window-minimize';
|
||||
// pluginIcon = 'pagination-plugin'; // 暂无新icon
|
||||
baseLayoutLIst = [
|
||||
lastLayoutSetting = ['pager'];
|
||||
layoutOptions = [
|
||||
{text: '总数', value: 'total', checked: false},
|
||||
{text: '每页条数', value: 'perPage', checked: false},
|
||||
{text: '分页', value: 'pager', checked: true},
|
||||
{text: '跳转', value: 'go', checked: false}
|
||||
{text: '跳转页', value: 'go', checked: false}
|
||||
];
|
||||
scaffold = {
|
||||
type: 'pagination',
|
||||
@ -66,27 +68,52 @@ export class PaginationPlugin extends BasePlugin {
|
||||
body: [
|
||||
{
|
||||
name: 'mode',
|
||||
label: '分页类型',
|
||||
label: '模式',
|
||||
type: 'button-group-select',
|
||||
size: 'sm',
|
||||
pipeIn: defaultValue('normal'),
|
||||
options: [
|
||||
{
|
||||
label: '普通',
|
||||
label: '默认',
|
||||
value: 'normal'
|
||||
},
|
||||
{
|
||||
label: '简易',
|
||||
label: '简约',
|
||||
value: 'simple'
|
||||
}
|
||||
]
|
||||
},
|
||||
// {
|
||||
// name: 'hasNext',
|
||||
// label: '是否有下一页',
|
||||
// mode: 'row',
|
||||
// inputClassName: 'inline-flex justify-between flex-row-reverse',
|
||||
// type: 'switch',
|
||||
// visibleOn: 'data.mode === "simple"'
|
||||
// },
|
||||
// {
|
||||
// name: 'activePage',
|
||||
// label: tipedLabel('当前页', '支持使用 \\${xxx} 来获取变量'),
|
||||
// type: 'input-text'
|
||||
// },
|
||||
// {
|
||||
// name: 'lastPage',
|
||||
// label: tipedLabel('最后页码', '支持使用 \\${xxx} 来获取变量'),
|
||||
// type: 'input-text',
|
||||
// visibleOn: 'data.mode === "normal"'
|
||||
// },
|
||||
// {
|
||||
// name: 'total',
|
||||
// label: tipedLabel('总条数', '支持使用 \\${xxx} 来获取变量'),
|
||||
// type: 'input-text',
|
||||
// visibleOn: 'data.mode === "normal"'
|
||||
// },
|
||||
getSchemaTpl('combo-container', {
|
||||
name: 'layout',
|
||||
type: 'combo',
|
||||
label: tipedLabel(
|
||||
'分页布局展示',
|
||||
'选中表示渲染该项,可以拖拽排序调整显示的顺序'
|
||||
'启用功能',
|
||||
'选中表示启用该项,可以拖拽排序调整功能的顺序'
|
||||
),
|
||||
visibleOn: 'data.mode === "normal"',
|
||||
mode: 'normal',
|
||||
@ -112,52 +139,37 @@ export class PaginationPlugin extends BasePlugin {
|
||||
}
|
||||
],
|
||||
pipeIn: (value: any) => {
|
||||
let layoutList: string[] = [];
|
||||
if (Array.isArray(value)) {
|
||||
layoutList = value;
|
||||
if (!value) {
|
||||
value = this.lastLayoutSetting;
|
||||
} else if (typeof value === 'string') {
|
||||
layoutList = (value as string).split(',');
|
||||
value = (value as string).split(',');
|
||||
}
|
||||
const layout = this.baseLayoutLIst.map(v => ({
|
||||
return this.layoutOptions.map(v => ({
|
||||
...v,
|
||||
checked: layoutList.includes(v.value)
|
||||
checked: value.includes(v.value)
|
||||
}));
|
||||
return layout;
|
||||
},
|
||||
pipeOut: (value: any[]) => {
|
||||
this.baseLayoutLIst = [...value];
|
||||
return value.filter(v => v.checked).map(v => v.value);
|
||||
this.lastLayoutSetting = value
|
||||
.filter(v => v.checked)
|
||||
.map(v => v.value);
|
||||
return this.lastLayoutSetting.concat();
|
||||
}
|
||||
}),
|
||||
{
|
||||
type: 'ae-formulaControl',
|
||||
label: '是否有下一页',
|
||||
name: 'hasNext',
|
||||
visibleOn: 'data.mode === "simple"'
|
||||
},
|
||||
{
|
||||
type: 'ae-formulaControl',
|
||||
label: '当前页',
|
||||
name: 'activePage'
|
||||
},
|
||||
{
|
||||
type: 'ae-formulaControl',
|
||||
label: '最后页码',
|
||||
name: 'lastPage',
|
||||
visibleOn: 'data.mode === "normal"'
|
||||
},
|
||||
{
|
||||
type: 'ae-formulaControl',
|
||||
label: '总条数',
|
||||
name: 'total',
|
||||
visibleOn: 'data.mode === "normal"'
|
||||
},
|
||||
// {
|
||||
// name: 'showPerPage',
|
||||
// label: '显示每页条数',
|
||||
// mode: 'row',
|
||||
// inputClassName: 'inline-flex justify-between flex-row-reverse',
|
||||
// type: 'switch',
|
||||
// visibleOn: 'data.mode === "normal"'
|
||||
// },
|
||||
getSchemaTpl('combo-container', {
|
||||
name: 'perPageAvailable',
|
||||
type: 'combo',
|
||||
label: '每页条数选项',
|
||||
visibleOn:
|
||||
'data.mode === "normal" && data.layout?.includes("perPage")',
|
||||
'data.mode === "normal" && data.layout && data.layout.includes("perPage")',
|
||||
mode: 'normal',
|
||||
multiple: true,
|
||||
multiLine: false,
|
||||
@ -167,6 +179,7 @@ export class PaginationPlugin extends BasePlugin {
|
||||
editable: true,
|
||||
minLength: 1,
|
||||
tabsStyle: 'inline',
|
||||
addButtonClassName: 'm-b-sm',
|
||||
items: [
|
||||
{
|
||||
type: 'input-number',
|
||||
@ -175,31 +188,35 @@ export class PaginationPlugin extends BasePlugin {
|
||||
}
|
||||
],
|
||||
pipeIn: (value: any[]) => {
|
||||
return value.map(v => ({value: v}));
|
||||
return value?.map(v => ({value: v})) || [10];
|
||||
},
|
||||
pipeOut: (value: any[]) => {
|
||||
return value.map(v => v.value);
|
||||
}
|
||||
}),
|
||||
{
|
||||
name: 'perPage',
|
||||
type: 'input-text',
|
||||
label: '默认每页条数',
|
||||
visibleOn:
|
||||
'data.mode === "normal" && data.layout?.includes("perPage")'
|
||||
},
|
||||
{
|
||||
name: 'maxButton',
|
||||
label: tipedLabel(
|
||||
'最多按钮数',
|
||||
'最多显示多少个分页按钮,最小为5,最大值为20'
|
||||
),
|
||||
type: 'input-number',
|
||||
min: 5,
|
||||
max: 20,
|
||||
pipeOut: (value: any) => value || 5,
|
||||
visibleOn: 'data.mode === "normal"'
|
||||
}
|
||||
})
|
||||
// {
|
||||
// name: 'perPage',
|
||||
// type: 'input-text',
|
||||
// label: '默认每页条数',
|
||||
// visibleOn: 'data.mode === "normal"'
|
||||
// },
|
||||
// {
|
||||
// name: 'maxButton',
|
||||
// label: tipedLabel('分页按钮数量', '超过此数量,将会隐藏多余按钮'),
|
||||
// type: 'input-number',
|
||||
// min: 5,
|
||||
// max: 20,
|
||||
// pipeIn: defaultValue(5),
|
||||
// visibleOn: 'data.mode === "normal"'
|
||||
// }
|
||||
// {
|
||||
// name: 'showPageInput',
|
||||
// label: '显示页面跳转',
|
||||
// mode: 'row',
|
||||
// inputClassName: 'inline-flex justify-between flex-row-reverse',
|
||||
// type: 'switch',
|
||||
// visibleOn: 'data.mode === "normal"'
|
||||
// }
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -85,7 +85,8 @@ export class PanelPlugin extends BasePlugin {
|
||||
panelJustify = true;
|
||||
|
||||
panelBodyCreator = (context: BaseEventContext) => {
|
||||
const isForm = /(?:^|\/)form$/.test(context.path) || context?.schema?.type === 'form';
|
||||
const isForm =
|
||||
/(?:^|\/)form$/.test(context.path) || context?.schema?.type === 'form';
|
||||
|
||||
return [
|
||||
getSchemaTpl('tabs', [
|
||||
@ -102,7 +103,7 @@ export class PanelPlugin extends BasePlugin {
|
||||
name: 'title',
|
||||
type: 'input-text'
|
||||
},
|
||||
|
||||
|
||||
isForm
|
||||
? null
|
||||
: {
|
||||
@ -124,7 +125,7 @@ export class PanelPlugin extends BasePlugin {
|
||||
]
|
||||
},
|
||||
getSchemaTpl('status')
|
||||
]),
|
||||
])
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -140,7 +141,7 @@ export class PanelPlugin extends BasePlugin {
|
||||
label: '固定底部',
|
||||
value: false
|
||||
}),
|
||||
|
||||
|
||||
getSchemaTpl('horizontal', {
|
||||
visibleOn:
|
||||
'(data.mode || data.$$formMode) == "horizontal" && data.$$mode == "form"'
|
||||
@ -152,7 +153,9 @@ export class PanelPlugin extends BasePlugin {
|
||||
title: '内容区域展示',
|
||||
body: [
|
||||
getSchemaTpl('subFormItemMode', {label: '表单展示模式'}),
|
||||
getSchemaTpl('subFormHorizontalMode', {label: '表单水平占比'}),
|
||||
getSchemaTpl('subFormHorizontalMode', {
|
||||
label: '表单水平占比'
|
||||
}),
|
||||
getSchemaTpl('subFormHorizontal')
|
||||
]
|
||||
},
|
||||
@ -211,28 +214,28 @@ export class PanelPlugin extends BasePlugin {
|
||||
name: isForm ? 'panelClassName' : 'className',
|
||||
pipeIn: defaultValue('Panel--default')
|
||||
}),
|
||||
|
||||
|
||||
getSchemaTpl('className', {
|
||||
name: 'headerClassName',
|
||||
label: '头部区域'
|
||||
}),
|
||||
|
||||
|
||||
getSchemaTpl('className', {
|
||||
name: 'bodyClassName',
|
||||
label: '内容区域'
|
||||
}),
|
||||
|
||||
|
||||
getSchemaTpl('className', {
|
||||
name: 'footerClassName',
|
||||
label: '底部区域'
|
||||
}),
|
||||
|
||||
|
||||
getSchemaTpl('className', {
|
||||
name: 'actionsClassName',
|
||||
label: '按钮外层'
|
||||
})
|
||||
],
|
||||
},
|
||||
]
|
||||
}
|
||||
])
|
||||
]
|
||||
}
|
||||
@ -251,9 +254,10 @@ export class PanelPlugin extends BasePlugin {
|
||||
if (
|
||||
context.info.renderer.name === 'form' &&
|
||||
schema.wrapWithPanel !== false &&
|
||||
!context.selections.length
|
||||
!context.selections.length &&
|
||||
false
|
||||
) {
|
||||
|
||||
/** Panel相关的配置融合到From中了 */
|
||||
panels.push({
|
||||
key: 'panel',
|
||||
icon: 'fa fa-list-alt',
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {registerEditorPlugin} from 'amis-editor-core';
|
||||
import {BaseEventContext, BasePlugin} from 'amis-editor-core';
|
||||
import {defaultValue, getSchemaTpl} from 'amis-editor-core';
|
||||
import {tipedLabel} from '../component/BaseControl';
|
||||
import {tipedLabel} from 'amis-editor-core';
|
||||
import {ValidatorTag} from '../validator';
|
||||
import {getEventControlConfig} from '../util';
|
||||
|
||||
|
@ -1,14 +1,19 @@
|
||||
import {Button} from 'amis';
|
||||
import React from 'react';
|
||||
import {registerEditorPlugin} from 'amis-editor-core';
|
||||
import {BaseEventContext, BasePlugin, RegionConfig} from 'amis-editor-core';
|
||||
import {getSchemaTpl} from 'amis-editor-core';
|
||||
import {getEventControlConfig} from '../util';
|
||||
|
||||
import type {
|
||||
import {
|
||||
getSchemaTpl,
|
||||
EditorManager,
|
||||
RendererPluginAction,
|
||||
RendererPluginEvent
|
||||
RendererPluginEvent,
|
||||
registerEditorPlugin,
|
||||
BaseEventContext,
|
||||
BasePlugin,
|
||||
RegionConfig,
|
||||
DSBuilderManager
|
||||
} from 'amis-editor-core';
|
||||
import {flattenDeep} from 'lodash';
|
||||
|
||||
export class ServicePlugin extends BasePlugin {
|
||||
// 关联渲染器名字
|
||||
@ -21,28 +26,30 @@ export class ServicePlugin extends BasePlugin {
|
||||
description =
|
||||
'功能性容器,可以用来加载数据或者加载渲染器配置。加载到的数据在容器可以使用。';
|
||||
docLink = '/amis/zh-CN/components/service';
|
||||
tags = ['功能'];
|
||||
tags = ['功能', '数据容器'];
|
||||
icon = 'fa fa-server';
|
||||
pluginIcon = 'service-plugin';
|
||||
scaffold = {
|
||||
type: 'service',
|
||||
body: []
|
||||
};
|
||||
previewSchema = {
|
||||
type: 'service',
|
||||
body: [
|
||||
{
|
||||
type: 'tpl',
|
||||
tpl: '内容',
|
||||
inline: false
|
||||
tpl: '内容区域',
|
||||
inline: false,
|
||||
className: 'bg-light wrapper'
|
||||
}
|
||||
]
|
||||
};
|
||||
previewSchema = {
|
||||
type: 'tpl',
|
||||
tpl: '功能性组件,用于数据拉取。'
|
||||
};
|
||||
|
||||
regions: Array<RegionConfig> = [
|
||||
{
|
||||
key: 'body',
|
||||
label: '内容区'
|
||||
label: '内容区域',
|
||||
placeholder: '内容区域'
|
||||
}
|
||||
];
|
||||
|
||||
@ -79,7 +86,30 @@ export class ServicePlugin extends BasePlugin {
|
||||
|
||||
panelTitle = '服务';
|
||||
|
||||
dsBuilderMgr: DSBuilderManager;
|
||||
|
||||
constructor(manager: EditorManager) {
|
||||
super(manager);
|
||||
this.dsBuilderMgr = new DSBuilderManager('service', 'api');
|
||||
}
|
||||
|
||||
panelBodyCreator = (context: BaseEventContext) => {
|
||||
const dsTypeSelect = () =>
|
||||
this.dsBuilderMgr.getDSSwitch({
|
||||
onChange: (value: any, oldValue: any, model: any, form: any) => {
|
||||
if (value !== oldValue) {
|
||||
const data = form.data;
|
||||
Object.keys(data).forEach(key => {
|
||||
if (key.endsWith('Fields') || key.toLowerCase().endsWith('api')) {
|
||||
form.deleteValueByName(key);
|
||||
}
|
||||
});
|
||||
form.deleteValueByName('__fields');
|
||||
}
|
||||
return value;
|
||||
}
|
||||
});
|
||||
|
||||
return getSchemaTpl('tabs', [
|
||||
{
|
||||
title: '属性',
|
||||
@ -89,87 +119,57 @@ export class ServicePlugin extends BasePlugin {
|
||||
{
|
||||
title: '基本',
|
||||
body: [
|
||||
getSchemaTpl('name'),
|
||||
{
|
||||
children: (
|
||||
<Button
|
||||
level="info"
|
||||
size="sm"
|
||||
className="m-b-sm"
|
||||
block
|
||||
onClick={() => {
|
||||
// this.manager.showInsertPanel('body', context.id);
|
||||
this.manager.showRendererPanel('');
|
||||
}}
|
||||
>
|
||||
添加内容
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '数据接口',
|
||||
body: [
|
||||
getSchemaTpl('apiControl', {
|
||||
name: 'api',
|
||||
label: '数据接口',
|
||||
messageDesc:
|
||||
'设置 service 默认提示信息,当 service 没有返回 msg 信息时有用,如果 service 返回携带了 msg 值,则还是以 service 返回为主'
|
||||
}),
|
||||
{
|
||||
name: 'ws',
|
||||
type: 'input-text',
|
||||
label: 'WebSocket 实时更新接口'
|
||||
},
|
||||
/** initFetchOn可以通过api的sendOn属性控制 */
|
||||
getSchemaTpl('switch', {
|
||||
name: 'initFetch',
|
||||
label: '数据接口初始加载',
|
||||
dsTypeSelect(),
|
||||
...this.dsBuilderMgr.collectFromBuilders(
|
||||
(builder, builderFlag) => {
|
||||
return {
|
||||
type: 'container',
|
||||
visibleOn: `this.dsType == null || this.dsType === '${builderFlag}'`,
|
||||
body: flattenDeep([
|
||||
builder.makeSourceSettingForm({
|
||||
name: 'api',
|
||||
label: '数据源',
|
||||
feat: 'View',
|
||||
inScaffold: false,
|
||||
inCrud: false
|
||||
})
|
||||
])
|
||||
};
|
||||
}
|
||||
),
|
||||
getSchemaTpl('initFetch', {
|
||||
visibleOn: 'this.api'
|
||||
}),
|
||||
{
|
||||
name: 'interval',
|
||||
label: '定时刷新间隔',
|
||||
visibleOn: 'this.api',
|
||||
type: 'input-number',
|
||||
step: 500,
|
||||
description: '设置后将自动定时刷新,单位 ms'
|
||||
},
|
||||
getSchemaTpl('switch', {
|
||||
name: 'silentPolling',
|
||||
label: '静默加载',
|
||||
visibleOn: '!!data.interval',
|
||||
description: '设置自动定时刷新是否显示加载动画'
|
||||
getSchemaTpl('interval', {
|
||||
visibleOn: 'this.api'
|
||||
}),
|
||||
{
|
||||
name: 'stopAutoRefreshWhen',
|
||||
label: '停止定时刷新检测',
|
||||
type: 'input-text',
|
||||
visibleOn: '!!data.interval',
|
||||
description:
|
||||
'定时刷新一旦设置会一直刷新,除非给出表达式,条件满足后则不刷新了。'
|
||||
}
|
||||
getSchemaTpl('silentPolling'),
|
||||
getSchemaTpl('stopAutoRefreshWhen')
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Schema接口',
|
||||
title: '状态',
|
||||
body: [getSchemaTpl('visible')]
|
||||
},
|
||||
{
|
||||
title: '高级',
|
||||
body: [
|
||||
getSchemaTpl('apiControl', {
|
||||
name: 'schemaApi',
|
||||
label: '内容 Schema 接口'
|
||||
label: 'Schema数据源'
|
||||
}),
|
||||
getSchemaTpl('switch', {
|
||||
getSchemaTpl('initFetch', {
|
||||
name: 'initFetchSchema',
|
||||
label: 'Schema接口初始加载',
|
||||
label: '是否Schema初始加载',
|
||||
visibleOn: 'this.schemaApi'
|
||||
})
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '全局配置',
|
||||
body: [
|
||||
}),
|
||||
{
|
||||
type: 'divider'
|
||||
},
|
||||
getSchemaTpl('data'),
|
||||
{
|
||||
type: 'divider'
|
||||
},
|
||||
{
|
||||
type: 'js-editor',
|
||||
allowFullscreen: true,
|
||||
@ -178,30 +178,14 @@ export class ServicePlugin extends BasePlugin {
|
||||
description: '将会传递 data 和 setData 两个参数'
|
||||
},
|
||||
{
|
||||
label: '默认消息信息',
|
||||
type: 'combo',
|
||||
name: 'messages',
|
||||
multiLine: true,
|
||||
description:
|
||||
'设置 service 默认提示信息,当 service 没有返回 msg 信息时有用,如果 service 返回携带了 msg 值,则还是以 service 返回为主',
|
||||
items: [
|
||||
{
|
||||
label: '获取成功',
|
||||
type: 'input-text',
|
||||
name: 'fetchSuccess'
|
||||
},
|
||||
{
|
||||
label: '获取失败',
|
||||
type: 'input-text',
|
||||
name: 'fetchFailed'
|
||||
}
|
||||
]
|
||||
type: 'divider'
|
||||
},
|
||||
{
|
||||
name: 'ws',
|
||||
type: 'input-text',
|
||||
label: 'WebSocket 实时更新接口'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
body: [getSchemaTpl('ref'), getSchemaTpl('visible')]
|
||||
}
|
||||
])
|
||||
]
|
||||
|
907
packages/amis-editor/src/plugin/Table-v2.tsx
Normal file
907
packages/amis-editor/src/plugin/Table-v2.tsx
Normal file
@ -0,0 +1,907 @@
|
||||
import {resolveVariable} from 'amis';
|
||||
|
||||
import {setVariable} from 'amis-core';
|
||||
import {
|
||||
BasePlugin,
|
||||
BaseEventContext,
|
||||
PluginEvent,
|
||||
RegionConfig,
|
||||
RendererInfoResolveEventContext,
|
||||
BasicRendererInfo,
|
||||
PluginInterface,
|
||||
InsertEventContext,
|
||||
ScaffoldForm,
|
||||
registerEditorPlugin,
|
||||
defaultValue,
|
||||
getSchemaTpl,
|
||||
tipedLabel,
|
||||
repeatArray,
|
||||
mockValue,
|
||||
EditorNodeType,
|
||||
RendererPluginAction,
|
||||
RendererPluginEvent
|
||||
} from 'amis-editor-core';
|
||||
import {getEventControlConfig} from '../util';
|
||||
import {SchemaObject} from 'amis/lib/Schema';
|
||||
import {getArgsWrapper} from '../renderer/event-control/helper';
|
||||
|
||||
export class TableV2Plugin extends BasePlugin {
|
||||
// 关联渲染器名字
|
||||
rendererName = 'table-v2';
|
||||
$schema = '/schemas/TableSchema.json';
|
||||
|
||||
// 组件名称
|
||||
name = '表格V2';
|
||||
isBaseComponent = true;
|
||||
panelJustify = true;
|
||||
description =
|
||||
'用来展示表格数据,可以配置列信息,然后关联数据便能完成展示。支持嵌套、超级表头、列固定、表头固顶、合并单元格等等。当前组件需要配置数据源,不自带数据拉取,请优先使用 「CRUD」 组件。';
|
||||
docLink = '/amis/zh-CN/components/table-v2';
|
||||
icon = 'fa fa-table';
|
||||
|
||||
scaffold: SchemaObject = {
|
||||
type: 'table-v2',
|
||||
|
||||
columns: [
|
||||
{
|
||||
title: '列信息',
|
||||
key: 'a'
|
||||
}
|
||||
],
|
||||
|
||||
source: '$item'
|
||||
};
|
||||
|
||||
regions: Array<RegionConfig> = [
|
||||
{
|
||||
key: 'columns',
|
||||
label: '列集合',
|
||||
renderMethod: 'renderTable',
|
||||
preferTag: '展示',
|
||||
dndMode: 'position-h'
|
||||
}
|
||||
];
|
||||
|
||||
previewSchema: any = {
|
||||
type: 'table-v2',
|
||||
className: 'text-left m-b-none',
|
||||
items: [
|
||||
{a: 1, b: 2, c: 9},
|
||||
{a: 3, b: 4, c: 8},
|
||||
{a: 5, b: 6, c: 7}
|
||||
],
|
||||
columns: [
|
||||
{
|
||||
title: 'A',
|
||||
key: 'a'
|
||||
},
|
||||
{
|
||||
title: 'B',
|
||||
key: 'b'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
scaffoldForm: ScaffoldForm = {
|
||||
title: '快速构建表格',
|
||||
body: [
|
||||
{
|
||||
name: 'columns',
|
||||
type: 'combo',
|
||||
multiple: true,
|
||||
label: false,
|
||||
addButtonText: '新增一列',
|
||||
draggable: true,
|
||||
items: [
|
||||
{
|
||||
type: 'input-text',
|
||||
name: 'title',
|
||||
placeholder: '标题'
|
||||
},
|
||||
{
|
||||
type: 'input-text',
|
||||
name: 'key',
|
||||
placeholder: '绑定字段名'
|
||||
},
|
||||
{
|
||||
type: 'select',
|
||||
name: 'type',
|
||||
placeholder: '类型',
|
||||
value: 'text',
|
||||
options: [
|
||||
{
|
||||
value: 'text',
|
||||
label: '纯文本'
|
||||
},
|
||||
{
|
||||
value: 'tpl',
|
||||
label: '模板'
|
||||
},
|
||||
{
|
||||
value: 'image',
|
||||
label: '图片'
|
||||
},
|
||||
{
|
||||
value: 'date',
|
||||
label: '日期'
|
||||
},
|
||||
{
|
||||
value: 'progress',
|
||||
label: '进度'
|
||||
},
|
||||
{
|
||||
value: 'status',
|
||||
label: '状态'
|
||||
},
|
||||
{
|
||||
value: 'mapping',
|
||||
label: '映射'
|
||||
},
|
||||
{
|
||||
value: 'container',
|
||||
label: '容器'
|
||||
},
|
||||
{
|
||||
value: 'operation',
|
||||
label: '操作栏'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
canRebuild: true
|
||||
};
|
||||
|
||||
panelTitle = '表格';
|
||||
|
||||
events: RendererPluginEvent[] = [
|
||||
{
|
||||
eventName: 'selectedChange',
|
||||
eventLabel: '选择表格项',
|
||||
description: '手动选择表格项事件',
|
||||
dataSchema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
'event.data.selectedItems': {
|
||||
type: 'array',
|
||||
title: '已选择行'
|
||||
},
|
||||
'event.data.unSelectedItems': {
|
||||
type: 'array',
|
||||
title: '未选择行'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
eventName: 'columnSort',
|
||||
eventLabel: '列排序',
|
||||
description: '点击列排序事件',
|
||||
dataSchema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
'event.data.orderBy': {
|
||||
type: 'string',
|
||||
title: '列排序列名'
|
||||
},
|
||||
'event.data.orderDir': {
|
||||
type: 'string',
|
||||
title: '列排序值'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
eventName: 'columnFilter',
|
||||
eventLabel: '列筛选',
|
||||
description: '点击列筛选事件',
|
||||
dataSchema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
'event.data.filterName': {
|
||||
type: 'string',
|
||||
title: '列筛选列名'
|
||||
},
|
||||
'event.data.filterValue': {
|
||||
type: 'string',
|
||||
title: '列筛选值'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
eventName: 'columnSearch',
|
||||
eventLabel: '列搜索',
|
||||
description: '点击列搜索事件',
|
||||
dataSchema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
'event.data.searchName': {
|
||||
type: 'string',
|
||||
title: '列搜索列名'
|
||||
},
|
||||
'event.data.searchValue': {
|
||||
type: 'object',
|
||||
title: '列搜索数据'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
eventName: 'orderChange',
|
||||
eventLabel: '行排序',
|
||||
description: '手动拖拽行排序事件',
|
||||
dataSchema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
'event.data.movedItems': {
|
||||
type: 'array',
|
||||
title: '已排序数据'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
eventName: 'columnToggled',
|
||||
eventLabel: '列显示变化',
|
||||
description: '点击自定义列事件',
|
||||
dataSchema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
'event.data.columns': {
|
||||
type: 'array',
|
||||
title: '当前显示的列配置数据'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
eventName: 'rowClick',
|
||||
eventLabel: '行单击',
|
||||
description: '点击整行事件',
|
||||
dataSchema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
'event.data.rowItem': {
|
||||
type: 'object',
|
||||
title: '行点击数据'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
actions: RendererPluginAction[] = [
|
||||
{
|
||||
actionType: 'select',
|
||||
actionLabel: '设置选中项',
|
||||
description: '设置表格的选中项',
|
||||
schema: getArgsWrapper([
|
||||
{
|
||||
type: 'input-formula',
|
||||
variables: '${variables}',
|
||||
evalMode: false,
|
||||
variableMode: 'tabs',
|
||||
label: '选中项',
|
||||
size: 'lg',
|
||||
name: 'selected',
|
||||
mode: 'horizontal'
|
||||
}
|
||||
])
|
||||
},
|
||||
{
|
||||
actionType: 'selectAll',
|
||||
actionLabel: '设置全部选中',
|
||||
description: '设置表格全部项选中'
|
||||
},
|
||||
{
|
||||
actionType: 'clearAll',
|
||||
actionLabel: '清空选中项',
|
||||
description: '清空表格所有选中项'
|
||||
}
|
||||
];
|
||||
|
||||
async buildDataSchemas(node: EditorNodeType, region?: EditorNodeType) {
|
||||
const itemsSchema: any = {
|
||||
$id: 'tableRow',
|
||||
type: 'object',
|
||||
properties: {}
|
||||
};
|
||||
const columns: EditorNodeType = node.children.find(
|
||||
item => item.isRegion && item.region === 'columns'
|
||||
);
|
||||
|
||||
for (let current of columns.children) {
|
||||
const schema = current.schema;
|
||||
if (schema && schema.key) {
|
||||
itemsSchema.properties[schema.key] = current.info?.plugin
|
||||
?.buildDataSchemas
|
||||
? await current.info.plugin.buildDataSchemas(current, region)
|
||||
: {
|
||||
type: 'string',
|
||||
title: schema.label || schema.title,
|
||||
description: schema.description
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const result: any = {
|
||||
$id: 'table-v2',
|
||||
type: 'object',
|
||||
properties: {
|
||||
items: {
|
||||
type: 'array',
|
||||
title: '表格数据',
|
||||
items: itemsSchema
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (region?.region === 'columns') {
|
||||
result.properties = {
|
||||
...itemsSchema.properties,
|
||||
...result.properties
|
||||
};
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async getAvailableContextFields(
|
||||
scopeNode: EditorNodeType,
|
||||
node: EditorNodeType,
|
||||
region?: EditorNodeType
|
||||
) {
|
||||
// // 只有表单项组件可以使用表单组件的数据域
|
||||
// if (
|
||||
// scopeNode.parent?.type === 'crud2'
|
||||
// ) {
|
||||
// return scopeNode.parent.info.plugin.getAvailableContextFields?.(
|
||||
// scopeNode.parent,
|
||||
// node,
|
||||
// region
|
||||
// );
|
||||
// }
|
||||
}
|
||||
|
||||
panelBodyCreator = (context: BaseEventContext) => {
|
||||
const isCRUDBody = ['crud', 'crud2'].includes(context.schema.type);
|
||||
|
||||
return getSchemaTpl('tabs', [
|
||||
{
|
||||
title: '属性',
|
||||
body: [
|
||||
getSchemaTpl('collapseGroup', [
|
||||
{
|
||||
title: '基本',
|
||||
body: [
|
||||
{
|
||||
name: 'source',
|
||||
type: 'input-text',
|
||||
label: tipedLabel('数据源', '绑定当前环境变量。'),
|
||||
hidden: isCRUDBody,
|
||||
pipeIn: defaultValue('${items}')
|
||||
},
|
||||
|
||||
getSchemaTpl('switch', {
|
||||
name: 'title',
|
||||
label: '显示标题',
|
||||
pipeIn: (value: any) => !!value,
|
||||
pipeOut: (value: any) => {
|
||||
if (value) {
|
||||
return {
|
||||
type: 'container',
|
||||
body: [
|
||||
{
|
||||
type: 'tpl',
|
||||
tpl: '表格标题',
|
||||
inline: false,
|
||||
style: {
|
||||
fontSize: 14
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}),
|
||||
|
||||
getSchemaTpl('switch', {
|
||||
name: 'showHeader',
|
||||
label: '显示表头',
|
||||
value: true,
|
||||
pipeIn: (value: any) => !!value,
|
||||
pipeOut: (value: any) => !!value
|
||||
}),
|
||||
|
||||
getSchemaTpl('switch', {
|
||||
visibleOn: 'this.showHeader !== false',
|
||||
name: 'sticky',
|
||||
label: '冻结表头',
|
||||
pipeIn: defaultValue(false)
|
||||
}),
|
||||
|
||||
getSchemaTpl('switch', {
|
||||
name: 'footer',
|
||||
label: '显示表尾',
|
||||
pipeIn: (value: any) => !!value,
|
||||
pipeOut: (value: any) => {
|
||||
if (value) {
|
||||
return {
|
||||
type: 'container',
|
||||
body: [
|
||||
{
|
||||
type: 'tpl',
|
||||
tpl: '表格尾部',
|
||||
inline: false,
|
||||
style: {
|
||||
fontSize: 14
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}),
|
||||
|
||||
{
|
||||
name: 'scroll.y',
|
||||
label: '内容高度',
|
||||
type: 'button-group-select',
|
||||
pipeIn: (v: any) => v != null,
|
||||
pipeOut: (v: any) => (v ? '' : null),
|
||||
options: [
|
||||
{
|
||||
label: '适配内容',
|
||||
value: false
|
||||
},
|
||||
|
||||
{
|
||||
label: '固定',
|
||||
value: true
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
type: 'input-group',
|
||||
visibleOn: 'data.scroll && data.scroll.y !== null',
|
||||
label: '高度值',
|
||||
body: [
|
||||
{
|
||||
type: 'input-number',
|
||||
name: 'scroll.y'
|
||||
},
|
||||
{
|
||||
type: 'tpl',
|
||||
addOnclassName: 'border-0 bg-none',
|
||||
tpl: 'px'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
name: 'scroll.x',
|
||||
label: tipedLabel(
|
||||
'内容宽度',
|
||||
'当列内容过多,超出宽度时,可使用横向滚动方式查看数据。'
|
||||
),
|
||||
type: 'button-group-select',
|
||||
pipeIn: (v: any) => v != null,
|
||||
pipeOut: (v: any) => (v ? '' : null),
|
||||
options: [
|
||||
{
|
||||
label: '适配内容',
|
||||
value: false
|
||||
},
|
||||
|
||||
{
|
||||
label: '固定',
|
||||
value: true
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
type: 'input-group',
|
||||
visibleOn: 'data.scroll && data.scroll.x !== null',
|
||||
name: 'scroll.x',
|
||||
label: '宽度值',
|
||||
body: [
|
||||
{
|
||||
type: 'input-number',
|
||||
name: 'scroll.x'
|
||||
},
|
||||
{
|
||||
type: 'tpl',
|
||||
addOnclassName: 'border-0 bg-none',
|
||||
tpl: 'px'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
name: 'placeholder',
|
||||
pipeIn: defaultValue('暂无数据'),
|
||||
type: 'input-text',
|
||||
label: '占位内容'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '列设置',
|
||||
body: [
|
||||
getSchemaTpl('switch', {
|
||||
name: 'resizable',
|
||||
label: tipedLabel('可调整列宽', '用户可通过拖拽调整列宽度'),
|
||||
pipeIn: (value: any) => !!value,
|
||||
pipeOut: (value: any) => value
|
||||
}),
|
||||
isCRUDBody
|
||||
? null
|
||||
: {
|
||||
type: 'ae-Switch-More',
|
||||
mode: 'normal',
|
||||
name: 'columnsTogglable',
|
||||
hiddenOnDefault: true,
|
||||
formType: 'extend',
|
||||
label: tipedLabel(
|
||||
'自定义显示列',
|
||||
'自动即列数量大于10自动开启。'
|
||||
),
|
||||
pipeOut: (value: any) => {
|
||||
if (value && value.columnsTogglable) {
|
||||
return {columnsTogglable: {type: 'column-toggler'}};
|
||||
}
|
||||
return value;
|
||||
},
|
||||
form: {
|
||||
body: [
|
||||
{
|
||||
mode: 'normal',
|
||||
type: 'ae-columnControl'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
title: '行设置',
|
||||
body: [
|
||||
{
|
||||
name: 'lineHeight',
|
||||
label: '行高度',
|
||||
type: 'select',
|
||||
placeholder: '请选择高度',
|
||||
options: [
|
||||
{label: '跟随内容', value: ''},
|
||||
{label: '高', value: 'large'},
|
||||
{label: '中', value: 'middle'}
|
||||
],
|
||||
clearable: false,
|
||||
value: ''
|
||||
},
|
||||
|
||||
isCRUDBody
|
||||
? {
|
||||
type: 'ae-Switch-More',
|
||||
mode: 'normal',
|
||||
name: 'rowSelection',
|
||||
label: '可多选',
|
||||
visibleOn: 'data.selectable',
|
||||
hiddenOnDefault: true,
|
||||
formType: 'extend',
|
||||
form: {
|
||||
body: [
|
||||
{
|
||||
label: '可选区域',
|
||||
name: 'rowSelection.rowClick',
|
||||
type: 'button-group-select',
|
||||
value: false,
|
||||
options: [
|
||||
{
|
||||
label: 'CheckBox',
|
||||
value: false
|
||||
},
|
||||
{
|
||||
label: '整行',
|
||||
value: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'rowSelection.disableOn',
|
||||
type: 'ae-formulaControl',
|
||||
label: '行禁用条件'
|
||||
},
|
||||
{
|
||||
name: 'rowSelection.selections',
|
||||
label: '选择菜单项',
|
||||
type: 'checkboxes',
|
||||
joinValues: false,
|
||||
inline: false,
|
||||
itemClassName: 'text-sm',
|
||||
options: [
|
||||
{label: '全选', value: 'all'},
|
||||
{label: '反选', value: 'invert'},
|
||||
{label: '取消选择', value: 'none'},
|
||||
{label: '选择奇数项', value: 'odd'},
|
||||
{label: '选择偶数项', value: 'even'}
|
||||
],
|
||||
pipeIn(v: any) {
|
||||
if (!v) {
|
||||
return;
|
||||
}
|
||||
return v.map((item: any) => ({
|
||||
label: item.text,
|
||||
value: item.key
|
||||
}));
|
||||
},
|
||||
pipeOut(v: any) {
|
||||
if (!v) {
|
||||
return;
|
||||
}
|
||||
return v.map((item: any) => ({
|
||||
key: item.value,
|
||||
text: item.label
|
||||
}));
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
: null,
|
||||
|
||||
{
|
||||
type: 'ae-Switch-More',
|
||||
mode: 'normal',
|
||||
name: 'expandable',
|
||||
label: '可展开',
|
||||
hiddenOnDefault: true,
|
||||
formType: 'extend',
|
||||
form: {
|
||||
body: [
|
||||
{
|
||||
name: 'expandable.expandableOn',
|
||||
visibleOn: 'data.expandable',
|
||||
type: 'ae-formulaControl',
|
||||
label: '行展开条件'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
getSchemaTpl('switch', {
|
||||
name: 'childrenColumnName',
|
||||
label: '可嵌套',
|
||||
pipeIn: (value: any) => !!value,
|
||||
pipeOut: (value: any) => (value ? 'children' : '')
|
||||
}),
|
||||
|
||||
getSchemaTpl('switch', {
|
||||
name: 'draggable',
|
||||
label: '可拖拽',
|
||||
pipeIn: (value: any) => !!value,
|
||||
pipeOut: (value: any) => value
|
||||
})
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
title: '状态',
|
||||
body: [
|
||||
getSchemaTpl('hidden', {
|
||||
label: '隐藏'
|
||||
})
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
title: '高级',
|
||||
body: [
|
||||
getSchemaTpl('apiControl', {
|
||||
label: '快速保存',
|
||||
name: 'quickSaveApi'
|
||||
}),
|
||||
|
||||
getSchemaTpl('apiControl', {
|
||||
label: '快速保存单条',
|
||||
name: 'quickSaveItemApi'
|
||||
})
|
||||
]
|
||||
}
|
||||
])
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '外观',
|
||||
body: [
|
||||
getSchemaTpl('collapseGroup', [
|
||||
{
|
||||
title: '基本',
|
||||
body: [
|
||||
getSchemaTpl('switch', {
|
||||
name: 'bordered',
|
||||
label: '边框',
|
||||
pipeIn: defaultValue(false)
|
||||
}),
|
||||
|
||||
{
|
||||
name: 'scroll.x',
|
||||
type: 'input-number',
|
||||
label: '横向滚动'
|
||||
},
|
||||
|
||||
{
|
||||
name: 'indentSize',
|
||||
visibleOn: 'data.childrenColumnName',
|
||||
type: 'input-number',
|
||||
unitOptions: [{label: 'px', value: 'px'}],
|
||||
label: '嵌套缩进'
|
||||
},
|
||||
|
||||
{
|
||||
name: 'rowSelection.columnWidth',
|
||||
visibleOn: 'data.rowSelection',
|
||||
type: 'input-number',
|
||||
label: '选择列宽度',
|
||||
description: '固定选择列的宽度'
|
||||
},
|
||||
|
||||
{
|
||||
name: 'expandable.columnWidth',
|
||||
visibleOn: 'data.expandable',
|
||||
type: 'input-number',
|
||||
label: '展开列宽度',
|
||||
description: '固定展开列的宽度'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
getSchemaTpl('style:classNames', {
|
||||
isFormItem: true,
|
||||
schema: [
|
||||
{
|
||||
name: 'rowClassNameExpr',
|
||||
type: 'ae-formulaControl',
|
||||
label: '自定义行样式'
|
||||
},
|
||||
|
||||
{
|
||||
name: 'expandable.expandedRowClassNameExpr',
|
||||
visibleOn: 'data.expandable',
|
||||
type: 'ae-formulaControl',
|
||||
label: '展开行样式'
|
||||
}
|
||||
]
|
||||
})
|
||||
])
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '事件',
|
||||
body: [
|
||||
getSchemaTpl('eventControl', {
|
||||
name: 'onEvent',
|
||||
...getEventControlConfig(this.manager, context)
|
||||
})
|
||||
]
|
||||
}
|
||||
]);
|
||||
};
|
||||
|
||||
filterProps(props: any) {
|
||||
const arr = Array.isArray(props.value)
|
||||
? props.value
|
||||
: typeof props.source === 'string'
|
||||
? resolveVariable(props.source, props.data)
|
||||
: resolveVariable('items', props.data);
|
||||
|
||||
if (!Array.isArray(arr) || !arr.length) {
|
||||
const mockedData: any = {};
|
||||
|
||||
if (Array.isArray(props.columns)) {
|
||||
props.columns.forEach((column: any) => {
|
||||
if (column.key) {
|
||||
setVariable(mockedData, column.key, mockValue(column));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
props.value = repeatArray(mockedData, 10).map((item, index) => ({
|
||||
...item,
|
||||
id: index + 1
|
||||
}));
|
||||
} else {
|
||||
// 只取10条预览,否则太多卡顿
|
||||
props.value = arr.slice(0, 10);
|
||||
}
|
||||
|
||||
// 如果设置了可展开 默认把第一行展开
|
||||
if (props.expandable) {
|
||||
if (typeof props.expandable === 'boolean') {
|
||||
props.expandable = {};
|
||||
}
|
||||
if (!props.expandable.type) {
|
||||
props.expandable.type = 'container';
|
||||
props.expandable.body = [
|
||||
{
|
||||
type: 'tpl',
|
||||
tpl: '展开行内容',
|
||||
inline: false
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
props.expandable.keyField = 'id';
|
||||
props.expandable.expandedRowKeys = [1];
|
||||
}
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
// 为了能够自动注入数据。
|
||||
getRendererInfo(
|
||||
context: RendererInfoResolveEventContext
|
||||
): BasicRendererInfo | void {
|
||||
const plugin: PluginInterface = this;
|
||||
const {schema, renderer} = context;
|
||||
|
||||
if (
|
||||
!schema.$$id &&
|
||||
['crud', 'crud2'].includes(schema.$$editor?.renderer.name) &&
|
||||
renderer.name === 'table-v2'
|
||||
) {
|
||||
return {
|
||||
...({id: schema.$$editor.id} as any),
|
||||
name: plugin.name!,
|
||||
regions: plugin.regions,
|
||||
patchContainers: plugin.patchContainers,
|
||||
vRendererConfig: plugin.vRendererConfig,
|
||||
wrapperProps: plugin.wrapperProps,
|
||||
wrapperResolve: plugin.wrapperResolve,
|
||||
filterProps: plugin.filterProps,
|
||||
$schema: plugin.$schema,
|
||||
renderRenderer: plugin.renderRenderer
|
||||
};
|
||||
}
|
||||
return super.getRendererInfo(context);
|
||||
}
|
||||
|
||||
// 自动插入 label
|
||||
beforeInsert(event: PluginEvent<InsertEventContext>) {
|
||||
const context = event.context;
|
||||
|
||||
if (
|
||||
(context.info.plugin === this ||
|
||||
context.node.sameIdChild?.info.plugin === this) &&
|
||||
context.region === 'columns'
|
||||
) {
|
||||
context.data = {
|
||||
...context.data,
|
||||
title: context.data.label ?? context.subRenderer?.name ?? '列名称'
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
registerEditorPlugin(TableV2Plugin);
|
588
packages/amis-editor/src/plugin/TableCell-v2.tsx
Normal file
588
packages/amis-editor/src/plugin/TableCell-v2.tsx
Normal file
@ -0,0 +1,588 @@
|
||||
import {Button, Icon} from 'amis';
|
||||
import React from 'react';
|
||||
import {FormItemProps, getVariable} from 'amis-core';
|
||||
|
||||
import {
|
||||
BasePlugin,
|
||||
BasicRendererInfo,
|
||||
registerEditorPlugin,
|
||||
RendererInfoResolveEventContext,
|
||||
ReplaceEventContext,
|
||||
PluginEvent,
|
||||
AfterBuildPanelBody,
|
||||
defaultValue,
|
||||
getSchemaTpl,
|
||||
tipedLabel,
|
||||
DSField
|
||||
} from 'amis-editor-core';
|
||||
import {fromPairs} from 'lodash';
|
||||
import {TabsSchema} from 'amis/lib/renderers/Tabs';
|
||||
import {SchemaObject} from 'amis/lib/Schema';
|
||||
import {remarkTpl} from '../component/BaseControl';
|
||||
|
||||
export class TableCellV2Plugin extends BasePlugin {
|
||||
panelTitle = '列配置';
|
||||
panelIcon = 'fa fa-columns';
|
||||
|
||||
afterBuildPanelBody(event: PluginEvent<AfterBuildPanelBody>) {
|
||||
const {context, data} = event.context;
|
||||
if (
|
||||
!context.node.parent?.parent?.type ||
|
||||
context.node.parent.parent.type !== 'table-v2'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
const base: Array<{
|
||||
sameName?: string;
|
||||
[propName: string]: any;
|
||||
}> = [
|
||||
context.node.info.plugin.withDataSource === false
|
||||
? false
|
||||
: {
|
||||
sameName: context.info.renderer.isFormItem ? 'name' : undefined,
|
||||
name: 'key',
|
||||
type: 'ae-DataBindingControl',
|
||||
label: '列字段',
|
||||
onBindingChange(
|
||||
field: DSField,
|
||||
onBulkChange: (value: any) => void
|
||||
) {
|
||||
const schema = field?.resolveColumnSchema?.('List') || {
|
||||
title: field.label
|
||||
};
|
||||
onBulkChange(schema);
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
sameName: context.info.renderer.isFormItem ? 'label' : undefined,
|
||||
name: 'title',
|
||||
label: '列标题',
|
||||
type: 'input-text'
|
||||
},
|
||||
|
||||
remarkTpl({
|
||||
name: 'remark',
|
||||
label: '标题提示',
|
||||
labelRemark: '在标题旁展示提示'
|
||||
}),
|
||||
|
||||
{
|
||||
name: 'placeholder',
|
||||
type: 'input-text',
|
||||
label: tipedLabel('占位提示', '当没有值时用这个来替代展示。'),
|
||||
value: '-'
|
||||
}
|
||||
].filter(Boolean);
|
||||
const advanced = [
|
||||
getSchemaTpl('switch', {
|
||||
name: 'sorter',
|
||||
label: tipedLabel(
|
||||
'可排序',
|
||||
'开启后可以根据当前列排序,接口类型将增加排序参数。'
|
||||
)
|
||||
}),
|
||||
|
||||
getSchemaTpl('switch', {
|
||||
name: 'searchable',
|
||||
label: '可搜索',
|
||||
pipeIn: (value: any) => !!value
|
||||
}),
|
||||
|
||||
{
|
||||
visibleOn: 'data.searchable',
|
||||
name: 'searchable',
|
||||
asFormItem: true,
|
||||
label: false,
|
||||
children: ({value, onChange, data}: any) => {
|
||||
if (value === true) {
|
||||
value = {};
|
||||
} else if (typeof value === 'undefined') {
|
||||
value = getVariable(data, 'searchable');
|
||||
}
|
||||
|
||||
const originMode = value.mode;
|
||||
|
||||
value = {
|
||||
...value,
|
||||
type: 'form',
|
||||
mode: 'normal',
|
||||
wrapWithPanel: false,
|
||||
body: [
|
||||
{
|
||||
type: 'input-text',
|
||||
name: data.key
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
delete value.mode;
|
||||
// todo 多个快速编辑表单模式看来只能代码模式编辑了。
|
||||
return (
|
||||
<Button
|
||||
className="w-full flex flex-col items-center"
|
||||
onClick={() => {
|
||||
this.manager.openSubEditor({
|
||||
title: '配置列搜索类型',
|
||||
value: value,
|
||||
onChange: value =>
|
||||
onChange(
|
||||
{
|
||||
...value,
|
||||
mode: originMode
|
||||
},
|
||||
'searchable'
|
||||
)
|
||||
});
|
||||
}}
|
||||
>
|
||||
<span className="inline-flex items-center">
|
||||
<Icon icon="edit" className="mr-1 w-3" />
|
||||
配置列搜索类型
|
||||
</span>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: 'quickEdit',
|
||||
label: tipedLabel('快速编辑', '输入框左侧或右侧的附加挂件'),
|
||||
type: 'ae-switch-more',
|
||||
mode: 'normal',
|
||||
formType: 'extend',
|
||||
bulk: true,
|
||||
defaultData: {
|
||||
mode: 'popOver'
|
||||
},
|
||||
form: {
|
||||
body: [
|
||||
{
|
||||
name: 'quickEdit.mode',
|
||||
type: 'button-group-select',
|
||||
label: '模式',
|
||||
value: 'popOver',
|
||||
options: [
|
||||
{
|
||||
label: '下拉',
|
||||
value: 'popOver'
|
||||
},
|
||||
{
|
||||
label: '内嵌',
|
||||
value: 'inline'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
getSchemaTpl('switch', {
|
||||
name: 'quickEdit.saveImmediately',
|
||||
label: tipedLabel(
|
||||
'修改立即保存',
|
||||
'开启后修改即提交,而不是批量提交。'
|
||||
),
|
||||
pipeIn: (value: any) => !!value
|
||||
}),
|
||||
|
||||
{
|
||||
name: 'quickEdit',
|
||||
asFormItem: true,
|
||||
label: false,
|
||||
children: ({value, onBulkChange, name, data}: any) => {
|
||||
if (value === true) {
|
||||
value = {};
|
||||
} else if (typeof value === 'undefined') {
|
||||
value = getVariable(data, 'quickEdit');
|
||||
}
|
||||
|
||||
const originMode = value?.mode || 'popOver';
|
||||
|
||||
value = {
|
||||
...value,
|
||||
type: 'form',
|
||||
mode: 'normal',
|
||||
wrapWithPanel: false,
|
||||
body: [
|
||||
{
|
||||
type: 'input-text',
|
||||
name: data.key
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
if (value.mode) {
|
||||
delete value.mode;
|
||||
}
|
||||
// todo 多个快速编辑表单模式看来只能代码模式编辑了。
|
||||
return (
|
||||
<Button
|
||||
className="w-full flex flex-col items-center"
|
||||
onClick={() => {
|
||||
this.manager.openSubEditor({
|
||||
title: '配置快速编辑类型',
|
||||
value: value,
|
||||
onChange: value =>
|
||||
onBulkChange({
|
||||
[name]: {
|
||||
...value,
|
||||
mode: originMode
|
||||
}
|
||||
})
|
||||
});
|
||||
}}
|
||||
>
|
||||
<span className="inline-flex items-center">
|
||||
<Icon icon="edit" className="mr-1 w-3" />
|
||||
配置编辑表单
|
||||
</span>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: 'popOver',
|
||||
label: '查看更多',
|
||||
type: 'ae-switch-more',
|
||||
mode: 'normal',
|
||||
formType: 'extend',
|
||||
bulk: true,
|
||||
form: {
|
||||
body: [
|
||||
{
|
||||
name: 'popOver.mode',
|
||||
label: '模式',
|
||||
type: 'button-group-select',
|
||||
pipeIn: defaultValue('popOver'),
|
||||
options: [
|
||||
{
|
||||
label: '浮窗',
|
||||
value: 'popOver'
|
||||
},
|
||||
|
||||
{
|
||||
label: '弹框',
|
||||
value: 'dialog'
|
||||
},
|
||||
|
||||
{
|
||||
label: '抽屉',
|
||||
value: 'drawer'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
name: 'popOver.position',
|
||||
label: '浮窗位置',
|
||||
type: 'select',
|
||||
visibleOn: 'data.popOver.mode === "popOver"',
|
||||
pipeIn: defaultValue('center'),
|
||||
options: [
|
||||
{
|
||||
label: '目标中部',
|
||||
value: 'center'
|
||||
},
|
||||
|
||||
{
|
||||
label: '目标左上角',
|
||||
value: 'left-top'
|
||||
},
|
||||
|
||||
{
|
||||
label: '目标右上角',
|
||||
value: 'right-top'
|
||||
},
|
||||
|
||||
{
|
||||
label: '目标左下角',
|
||||
value: 'left-bottom'
|
||||
},
|
||||
|
||||
{
|
||||
label: '目标右下角',
|
||||
value: 'right-bottom'
|
||||
},
|
||||
|
||||
{
|
||||
label: '页面左上角',
|
||||
value: 'fixed-left-top'
|
||||
},
|
||||
|
||||
{
|
||||
label: '页面右上角',
|
||||
value: 'fixed-right-top'
|
||||
},
|
||||
|
||||
{
|
||||
label: '页面左下角',
|
||||
value: 'fixed-left-bottom'
|
||||
},
|
||||
|
||||
{
|
||||
label: '页面右下角',
|
||||
value: 'fixed-right-bottom'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
name: 'popOver',
|
||||
asFormItem: true,
|
||||
label: false,
|
||||
children: ({value, onBulkChange, name}: any) => {
|
||||
value = {
|
||||
type: 'panel',
|
||||
title: '查看详情',
|
||||
body: '内容详情',
|
||||
...value
|
||||
};
|
||||
|
||||
return (
|
||||
<Button
|
||||
className="w-full flex flex-col items-center"
|
||||
onClick={() => {
|
||||
this.manager.openSubEditor({
|
||||
title: '配置查看更多展示内容',
|
||||
value: value,
|
||||
onChange: value =>
|
||||
onBulkChange({
|
||||
[name]: value
|
||||
})
|
||||
});
|
||||
}}
|
||||
>
|
||||
<span className="inline-flex items-center">
|
||||
<Icon icon="edit" className="mr-1 w-3" />
|
||||
配置内容
|
||||
</span>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: 'copyable',
|
||||
label: tipedLabel('复制内容', '默认为当前字段值,可定制。'),
|
||||
type: 'ae-switch-more',
|
||||
mode: 'normal',
|
||||
formType: 'extend',
|
||||
bulk: true,
|
||||
defaultData: {},
|
||||
form: {
|
||||
body: [
|
||||
{
|
||||
name: 'copyable.content',
|
||||
type: 'textarea',
|
||||
placehoder: '默认为当前字段的值',
|
||||
label: '内容模板'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
name: 'rowSpanExpr',
|
||||
type: 'ae-formulaControl',
|
||||
label: '合并行'
|
||||
},
|
||||
{
|
||||
name: 'colSpanExpr',
|
||||
type: 'ae-formulaControl',
|
||||
label: '合并列'
|
||||
}
|
||||
];
|
||||
|
||||
const baseStyle = [
|
||||
getSchemaTpl('withUnit', {
|
||||
name: 'width',
|
||||
label: tipedLabel('列宽', '固定列的宽度,不推荐设置。'),
|
||||
control: {
|
||||
name: 'width',
|
||||
type: 'input-number'
|
||||
},
|
||||
unit: 'px'
|
||||
}),
|
||||
|
||||
{
|
||||
name: 'fixed',
|
||||
type: 'button-group-select',
|
||||
label: '固定位置',
|
||||
pipeIn: defaultValue(''),
|
||||
pipeOut(value: any) {
|
||||
if (!value) {
|
||||
return undefined;
|
||||
}
|
||||
return value;
|
||||
},
|
||||
options: [
|
||||
{
|
||||
value: '',
|
||||
label: '不固定'
|
||||
},
|
||||
|
||||
{
|
||||
value: 'left',
|
||||
label: '左侧'
|
||||
},
|
||||
|
||||
{
|
||||
value: 'right',
|
||||
label: '右侧'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
getSchemaTpl('switch', {
|
||||
name: 'toggled',
|
||||
label: '自定义列时默认展示',
|
||||
pipeIn: defaultValue(true)
|
||||
}),
|
||||
|
||||
getSchemaTpl('switch', {
|
||||
name: 'className',
|
||||
label: '内容超出换行',
|
||||
pipeIn: (value: any) =>
|
||||
typeof value === 'string' && /\word\-break\b/.test(value),
|
||||
pipeOut: (value: any, originValue: any) =>
|
||||
(value ? 'word-break ' : '') +
|
||||
(originValue || '').replace(/\bword\-break\b/g, '').trim()
|
||||
})
|
||||
];
|
||||
|
||||
// 之前的面板,不是新的组件面板,需要添加新的tab,不能合并
|
||||
if (Array.isArray(data)) {
|
||||
if ((data[0] as SchemaObject).type === 'tabs') {
|
||||
const body = data[0] as TabsSchema;
|
||||
body.tabs.forEach((tab: any) => {
|
||||
if (tab.title === '常规') {
|
||||
tab.body.unshift(...base.concat(advanced));
|
||||
}
|
||||
|
||||
if (tab.title === '外观') {
|
||||
tab.body.unshift(...baseStyle);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.error('错误的组件合并对象,面板过老无法处理,除非增加新面板');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
(data as TabsSchema).tabs?.forEach((tab: any) => {
|
||||
if (tab.title === '属性') {
|
||||
tab.body[0].body.forEach((collapse: any) => {
|
||||
if (collapse.title === '基本') {
|
||||
const appendItems = fromPairs(
|
||||
base.map(item => [item.sameName ?? item.name, item])
|
||||
);
|
||||
|
||||
const removeIndex: number[] = [];
|
||||
collapse.body.forEach((item: any, index: number) => {
|
||||
const key = item.name;
|
||||
|
||||
// 重复意义的配置用现在的表达文案替换一下
|
||||
if (appendItems.hasOwnProperty(key)) {
|
||||
removeIndex.push(index);
|
||||
appendItems[key] = {
|
||||
...item,
|
||||
...appendItems[key]
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.name === 'labelRemark') {
|
||||
removeIndex.push(index);
|
||||
}
|
||||
});
|
||||
|
||||
removeIndex.reverse();
|
||||
removeIndex.forEach(index => {
|
||||
collapse.body.splice(index, 1);
|
||||
});
|
||||
|
||||
collapse.body.unshift(...Object.values(appendItems));
|
||||
}
|
||||
});
|
||||
|
||||
const moreCollapse = getSchemaTpl('collapseGroup', [
|
||||
{
|
||||
title: '列',
|
||||
body: advanced
|
||||
}
|
||||
]);
|
||||
tab.body[0].body.splice(1, 0, ...moreCollapse.body);
|
||||
// 让折叠器默认都展开
|
||||
tab.body[0].activeKey.push(...moreCollapse.activeKey);
|
||||
}
|
||||
|
||||
if (tab.title === '外观') {
|
||||
const moreCollapse = getSchemaTpl('collapseGroup', [
|
||||
{
|
||||
title: '列',
|
||||
body: baseStyle
|
||||
}
|
||||
]);
|
||||
tab.body[0].body.splice(1, 0, ...moreCollapse.body);
|
||||
// 让折叠器默认都展开
|
||||
tab.body[0].activeKey.push(...moreCollapse.activeKey);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// filterProps(props: any) {
|
||||
// props = JSONPipeOut(props, true);
|
||||
// return props;
|
||||
// }
|
||||
|
||||
getRendererInfo(
|
||||
context: RendererInfoResolveEventContext
|
||||
): BasicRendererInfo | void {
|
||||
const {renderer, schema} = context;
|
||||
|
||||
if (renderer.name === 'cell-field') {
|
||||
return {
|
||||
name: schema.title ? `<${schema.title}>列` : '匿名列',
|
||||
$schema: '/schemas/TableColumn.json',
|
||||
multifactor: true,
|
||||
wrapperResolve: (dom: HTMLDivElement) => {
|
||||
// 固定这种结构 amis里改了 这里也得改
|
||||
const parent = dom.parentElement?.parentElement;
|
||||
const groupId = parent?.getAttribute('data-group-id');
|
||||
const wrapper = dom.closest('table')!.parentElement?.parentElement;
|
||||
|
||||
return [].slice.call(
|
||||
wrapper?.querySelectorAll(
|
||||
`th[data-group-id="${groupId}"],
|
||||
td[data-group-id="${groupId}"]`
|
||||
)
|
||||
);
|
||||
}
|
||||
// filterProps: this.filterProps
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/*exchangeRenderer(id: string) {
|
||||
this.manager.showReplacePanel(id, '展示');
|
||||
}*/
|
||||
|
||||
beforeReplace(event: PluginEvent<ReplaceEventContext>) {
|
||||
const context = event.context;
|
||||
|
||||
// 替换字段的时候保留 label 和 name 值。
|
||||
if (context.info.plugin === this && context.data) {
|
||||
context.data.title = context.data.title || context.schema.title;
|
||||
context.data.key = context.data.key || context.schema.key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
registerEditorPlugin(TableCellV2Plugin);
|
@ -16,10 +16,10 @@ import {VRenderer} from 'amis-editor-core';
|
||||
import findIndex from 'lodash/findIndex';
|
||||
import {RegionWrapper as Region} from 'amis-editor-core';
|
||||
import {Tab} from 'amis';
|
||||
import {tipedLabel} from '../component/BaseControl';
|
||||
import {tipedLabel} from 'amis-editor-core';
|
||||
import {ValidatorTag} from '../validator';
|
||||
import {getEventControlConfig} from '../util';
|
||||
import { getArgsWrapper } from '../renderer/event-control/helper';
|
||||
import {getArgsWrapper} from '../renderer/event-control/helper';
|
||||
|
||||
export class TabsPlugin extends BasePlugin {
|
||||
// 关联渲染器名字
|
||||
|
@ -5,7 +5,7 @@
|
||||
import {registerEditorPlugin} from 'amis-editor-core';
|
||||
import {BasePlugin, RegionConfig, BaseEventContext} from 'amis-editor-core';
|
||||
import {defaultValue, getSchemaTpl} from 'amis-editor-core';
|
||||
import {tipedLabel} from '../component/BaseControl';
|
||||
import {tipedLabel} from 'amis-editor-core';
|
||||
|
||||
export class TooltipWrapperPlugin extends BasePlugin {
|
||||
rendererName = 'tooltip-wrapper';
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {registerEditorPlugin} from 'amis-editor-core';
|
||||
import {BaseEventContext, BasePlugin} from 'amis-editor-core';
|
||||
import {defaultValue, getSchemaTpl, setSchemaTpl} from 'amis-editor-core';
|
||||
import {tipedLabel} from '../component/BaseControl';
|
||||
import {tipedLabel} from 'amis-editor-core';
|
||||
import {ValidatorTag} from '../validator';
|
||||
import {getEventControlConfig} from '../util';
|
||||
|
||||
@ -146,7 +146,7 @@ export class TplPlugin extends BasePlugin {
|
||||
),
|
||||
name: 'inline',
|
||||
pipeIn: defaultValue(true),
|
||||
hiddenOn:'data.wrapperComponent !== ""'
|
||||
hiddenOn: 'data.wrapperComponent !== ""'
|
||||
}),
|
||||
getSchemaTpl('tpl:content'),
|
||||
getSchemaTpl('tpl:rich-text')
|
||||
|
@ -5,7 +5,7 @@ import {
|
||||
getSchemaTpl
|
||||
} from 'amis-editor-core';
|
||||
import '@webcomponents/webcomponentsjs/custom-elements-es5-adapter';
|
||||
import {tipedLabel} from '../component/BaseControl';
|
||||
import {tipedLabel} from 'amis-editor-core';
|
||||
|
||||
// 需要一个示例,不然默认的没有高度都无法选中
|
||||
class WebComponentDemo extends HTMLElement {
|
||||
@ -67,7 +67,7 @@ export class WebComponentPlugin extends BasePlugin {
|
||||
mode: 'normal',
|
||||
name: 'props',
|
||||
label: '属性'
|
||||
}),
|
||||
})
|
||||
]
|
||||
}
|
||||
])
|
||||
|
@ -1,26 +1,43 @@
|
||||
import React from 'react';
|
||||
import merge from 'lodash/merge';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import cx from 'classnames';
|
||||
import {FormItem, InputBox, Icon} from 'amis';
|
||||
import {} from 'amis-ui';
|
||||
import {PickerContainer} from 'amis';
|
||||
import {FormItem, Icon} from 'amis';
|
||||
import {Input, PickerContainer, Spinner} from 'amis-ui';
|
||||
|
||||
import {getEnv} from 'mobx-state-tree';
|
||||
import {normalizeApi, isEffectiveApi, isApiOutdated} from 'amis-core';
|
||||
|
||||
import {isObject, autobind, createObject, anyChanged} from 'amis-editor-core';
|
||||
import {tipedLabel} from '../component/BaseControl';
|
||||
import {isObject, autobind, createObject, tipedLabel} from 'amis-editor-core';
|
||||
|
||||
import type {SchemaObject, SchemaCollection, SchemaApi} from 'amis/lib/Schema';
|
||||
import type {Api} from 'amis/lib/types';
|
||||
import type {FormControlProps} from 'amis-core';
|
||||
import type {ActionSchema} from 'amis/lib/renderers/Action';
|
||||
|
||||
export type ApiObject = Api & {
|
||||
messages?: Record<
|
||||
| 'fetchSuccess'
|
||||
| 'fetchFailed'
|
||||
| 'saveOrderSuccess'
|
||||
| 'saveOrderFailed'
|
||||
| 'quickSaveSuccess'
|
||||
| 'quickSaveFailed',
|
||||
string
|
||||
>;
|
||||
};
|
||||
|
||||
export interface APIControlProps extends FormControlProps {
|
||||
name?: string;
|
||||
label?: string;
|
||||
value?: any;
|
||||
|
||||
/**
|
||||
* 开启debug模式
|
||||
*/
|
||||
debug?: boolean;
|
||||
|
||||
/**
|
||||
* 接口消息设置描述信息
|
||||
*/
|
||||
@ -76,6 +93,36 @@ export interface APIControlProps extends FormControlProps {
|
||||
*/
|
||||
pickerHeaderClassName?: string;
|
||||
|
||||
/**
|
||||
* 是否只返回内部TabsPanel
|
||||
*/
|
||||
onlyTabs?: boolean;
|
||||
|
||||
/**
|
||||
* 开启高亮显示
|
||||
*/
|
||||
enableHighlight?: boolean;
|
||||
|
||||
/**
|
||||
* Picker选项的label字段
|
||||
*/
|
||||
labelField?: string;
|
||||
|
||||
/**
|
||||
* 检索字段
|
||||
*/
|
||||
searchField?: string;
|
||||
|
||||
/**
|
||||
* 检索字段类型
|
||||
*/
|
||||
searchType?: string;
|
||||
|
||||
/**
|
||||
* 底部区域CSS类名
|
||||
*/
|
||||
footerClassName?: string;
|
||||
|
||||
/**
|
||||
* Picker面板确认
|
||||
*/
|
||||
@ -103,38 +150,52 @@ export interface APIControlState {
|
||||
apiStr: string;
|
||||
selectedItem?: any[];
|
||||
schema?: SchemaCollection;
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
export default class APIControl extends React.Component<
|
||||
APIControlProps,
|
||||
APIControlState
|
||||
> {
|
||||
static defaultProps: Pick<APIControlProps, 'pickerBtnSchema'> = {
|
||||
input?: HTMLInputElement;
|
||||
|
||||
static defaultProps: Pick<
|
||||
APIControlProps,
|
||||
'pickerBtnSchema' | 'labelField' | 'searchType'
|
||||
> = {
|
||||
pickerBtnSchema: {
|
||||
type: 'button',
|
||||
level: 'link',
|
||||
size: 'sm',
|
||||
label: '点击选择'
|
||||
}
|
||||
size: 'sm'
|
||||
},
|
||||
labelField: 'label',
|
||||
searchType: 'key'
|
||||
};
|
||||
|
||||
constructor(props: APIControlProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
apiStr: this.transformApi2Str(props.value),
|
||||
selectedItem: [],
|
||||
schema: props.pickerSchema
|
||||
schema: props.pickerSchema,
|
||||
loading: false
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.updatePickerOptions();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: APIControlProps) {
|
||||
const props = this.props;
|
||||
|
||||
if (prevProps.value !== props.value) {
|
||||
if (!isEqual(prevProps?.value, props?.value)) {
|
||||
this.setState({apiStr: this.transformApi2Str(props.value)});
|
||||
this.updatePickerOptions();
|
||||
}
|
||||
|
||||
if (anyChanged(['enablePickerMode', 'pickerSchema'], prevProps, props)) {
|
||||
if (!isEqual(prevProps?.enablePickerMode, props?.enablePickerMode)) {
|
||||
this.setState({schema: props.pickerSchema});
|
||||
}
|
||||
|
||||
@ -150,23 +211,52 @@ export default class APIControl extends React.Component<
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 已选API详情,因为list接口是分页的,所以需要单独调用一次
|
||||
*/
|
||||
async updatePickerOptions() {
|
||||
const apiObj = normalizeApi(this.props.value);
|
||||
|
||||
if (apiObj?.url?.startsWith('api://')) {
|
||||
this.setState({loading: true});
|
||||
const keyword = apiObj.url.replace('api://', '');
|
||||
|
||||
try {
|
||||
await this.fetchOptions(keyword);
|
||||
} catch (error) {}
|
||||
}
|
||||
this.setState({loading: false});
|
||||
}
|
||||
|
||||
transformApi2Str(value: any) {
|
||||
const api = normalizeApi(value);
|
||||
|
||||
return api.url ? `${api.method ? `${api.method}:` : ''}${api.url}` : '';
|
||||
return api.url
|
||||
? `${
|
||||
api.method &&
|
||||
api.method.toLowerCase() !==
|
||||
'get' /** 默认为GET请求,直接隐藏掉前缀,为了呈现更多信息 */
|
||||
? `${api.method}:`
|
||||
: ''
|
||||
}${api.url}`
|
||||
: '';
|
||||
}
|
||||
|
||||
async fetchOptions() {
|
||||
const {value, data, env} = this.props;
|
||||
async fetchOptions(keyword?: string) {
|
||||
const {value, data, env, searchField, searchType} = this.props;
|
||||
let {pickerSource} = this.props;
|
||||
const apiObj = normalizeApi(value);
|
||||
const apiKey = apiObj?.url.split('api://')?.[1];
|
||||
|
||||
if (!pickerSource) {
|
||||
if (!pickerSource || !apiObj?.url) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ctx = createObject(data, {value, op: 'loadOptions'});
|
||||
const apiKey = apiObj?.url?.split('api://')?.[1];
|
||||
const ctx = createObject(data, {
|
||||
value,
|
||||
op: 'loadOptions',
|
||||
...(keyword && searchField ? {[searchField]: keyword, searchType} : {})
|
||||
});
|
||||
const schemaFilter = getEnv((window as any).editorStore).schemaFilter;
|
||||
|
||||
// 基于爱速搭的规则转换一下
|
||||
@ -177,6 +267,7 @@ export default class APIControl extends React.Component<
|
||||
if (isEffectiveApi(pickerSource, ctx)) {
|
||||
const res = await env.fetcher(pickerSource, ctx);
|
||||
const items: any[] = res.data?.items || res?.data?.rows;
|
||||
|
||||
if (items.length) {
|
||||
const selectedItem = items.find(item => item.key === apiKey);
|
||||
|
||||
@ -186,7 +277,40 @@ export default class APIControl extends React.Component<
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleSubmit(values: SchemaApi, action: any) {
|
||||
inputRef(ref: any) {
|
||||
this.input = ref;
|
||||
}
|
||||
|
||||
focus() {
|
||||
if (!this.input) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.input.focus();
|
||||
}
|
||||
|
||||
@autobind
|
||||
clearPickerValue() {
|
||||
const {onChange} = this.props;
|
||||
|
||||
this.setState(
|
||||
{apiStr: this.transformApi2Str(undefined), selectedItem: []},
|
||||
() => {
|
||||
onChange?.(undefined);
|
||||
this.focus();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleSimpleInputChange(e: React.ChangeEvent<HTMLInputElement>) {
|
||||
const value = e.currentTarget.value;
|
||||
|
||||
this.handleSubmit(value, 'input');
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleSubmit(values: SchemaApi, action?: 'input' | 'picker-submit') {
|
||||
const {onChange, value} = this.props;
|
||||
let api: Api = values;
|
||||
|
||||
@ -241,7 +365,7 @@ export default class APIControl extends React.Component<
|
||||
}
|
||||
|
||||
renderHeader() {
|
||||
const {render, actions, enablePickerMode} = this.props;
|
||||
const {render, actions} = this.props;
|
||||
|
||||
const actionsDom =
|
||||
Array.isArray(actions) && actions.length > 0
|
||||
@ -253,9 +377,9 @@ export default class APIControl extends React.Component<
|
||||
})
|
||||
: null;
|
||||
|
||||
return actionsDom || enablePickerMode ? (
|
||||
return actionsDom ? (
|
||||
<header className="ae-ApiControl-header" key="header">
|
||||
{enablePickerMode ? this.renderPickerSchema() : actionsDom}
|
||||
{actionsDom}
|
||||
</header>
|
||||
) : null;
|
||||
}
|
||||
@ -280,14 +404,19 @@ export default class APIControl extends React.Component<
|
||||
return (
|
||||
<PickerContainer
|
||||
title={pickerTitle}
|
||||
value={selectedItem}
|
||||
headerClassName={cx(pickerHeaderClassName, 'font-bold')}
|
||||
onConfirm={this.handlePickerConfirm}
|
||||
onCancel={this.handlePickerClose}
|
||||
size={pickerSize}
|
||||
bodyRender={({value, onClose, onChange, setState, ...states}) => {
|
||||
bodyRender={({
|
||||
onChange,
|
||||
setState
|
||||
}: {
|
||||
onChange: (value: any) => void;
|
||||
setState: (state: any) => void;
|
||||
}) => {
|
||||
return render('api-control-picker', schema!, {
|
||||
data: {[pickerName]: selectedItem},
|
||||
value: selectedItem,
|
||||
onSelect: (items: Array<any>) => {
|
||||
setState({selectedItem: items});
|
||||
onChange(this.normalizeValue(items, onPickerSelect));
|
||||
@ -295,32 +424,50 @@ export default class APIControl extends React.Component<
|
||||
});
|
||||
}}
|
||||
>
|
||||
{({onClick, isOpened}) =>
|
||||
render('picker-action', pickerBtnSchema!, {
|
||||
onClick: async (e: React.MouseEvent<any>) => {
|
||||
if (!isOpened && enablePickerMode) {
|
||||
try {
|
||||
await this.fetchOptions();
|
||||
} catch {}
|
||||
}
|
||||
{({
|
||||
onClick,
|
||||
isOpened
|
||||
}: {
|
||||
onClick: (e: React.MouseEvent) => void;
|
||||
isOpened: boolean;
|
||||
}) =>
|
||||
render(
|
||||
'picker-action',
|
||||
{
|
||||
icon: (
|
||||
<Icon icon="picker-icon" className="icon ae-ApiControl-icon" />
|
||||
),
|
||||
...pickerBtnSchema!,
|
||||
className: cx(
|
||||
'ae-ApiControl-PickerBtn',
|
||||
pickerBtnSchema?.className
|
||||
)
|
||||
},
|
||||
{
|
||||
onClick: async (e: React.MouseEvent<any>) => {
|
||||
if (!isOpened && enablePickerMode) {
|
||||
try {
|
||||
await this.fetchOptions();
|
||||
} catch {}
|
||||
}
|
||||
|
||||
onClick(e);
|
||||
onClick(e);
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
</PickerContainer>
|
||||
);
|
||||
}
|
||||
|
||||
renderApiDialog() {
|
||||
const {messageDesc} = this.props;
|
||||
|
||||
return {
|
||||
label: '',
|
||||
type: 'action',
|
||||
acitonType: 'dialog',
|
||||
size: 'sm',
|
||||
icon: <Icon icon="api" />,
|
||||
icon: <Icon icon="setting" className="icon ae-ApiControl-icon" />,
|
||||
className: 'ae-ApiControl-setting-button',
|
||||
actionType: 'dialog',
|
||||
dialog: {
|
||||
title: '高级设置',
|
||||
@ -331,12 +478,14 @@ export default class APIControl extends React.Component<
|
||||
closeOnEsc: true,
|
||||
closeOnOutside: false,
|
||||
showCloseButton: true,
|
||||
body: [this.renderApiConfigTabs(messageDesc)]
|
||||
body: [this.renderApiConfigTabs()]
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
renderApiConfigTabs(messageDesc?: string, submitOnChange: boolean = false) {
|
||||
renderApiConfigTabs(submitOnChange: boolean = false) {
|
||||
const {messageDesc, debug = false} = this.props;
|
||||
|
||||
return {
|
||||
type: 'form',
|
||||
className: 'ae-ApiControl-form',
|
||||
@ -344,6 +493,7 @@ export default class APIControl extends React.Component<
|
||||
submitOnChange,
|
||||
wrapWithPanel: false,
|
||||
onSubmit: this.handleSubmit,
|
||||
debug,
|
||||
body: [
|
||||
{
|
||||
type: 'tabs',
|
||||
@ -462,75 +612,6 @@ export default class APIControl extends React.Component<
|
||||
mode: 'horizontal',
|
||||
description: '默认数据为追加方式,开启后完全替换当前数据'
|
||||
},
|
||||
{
|
||||
label: tipedLabel(
|
||||
'初始加载',
|
||||
'当配置初始化接口后,组件初始就会拉取接口数据,可以通过以下配置修改'
|
||||
),
|
||||
type: 'group',
|
||||
visibleOn: 'this.initApi',
|
||||
mode: 'horizontal',
|
||||
direction: 'vertical',
|
||||
// labelRemark: {
|
||||
// trigger: 'hover',
|
||||
// rootClose: true,
|
||||
// content:
|
||||
// '当配置初始化接口后,组件初始就会拉取接口数据,可以通过以下配置修改',
|
||||
// placement: 'top'
|
||||
// },
|
||||
|
||||
body: [
|
||||
{
|
||||
name: 'initFetch',
|
||||
type: 'radios',
|
||||
inline: true,
|
||||
mode: 'normal',
|
||||
renderLabel: false,
|
||||
onChange: () => {
|
||||
document.getElementsByClassName(
|
||||
'ae-Settings-content'
|
||||
)[0].scrollTop = 0;
|
||||
},
|
||||
// pipeIn: (value:any) => typeof value === 'boolean' ? value : '1'
|
||||
options: [
|
||||
{
|
||||
label: '是',
|
||||
value: true
|
||||
},
|
||||
|
||||
{
|
||||
label: '否',
|
||||
value: false
|
||||
},
|
||||
|
||||
{
|
||||
label: '表达式',
|
||||
value: ''
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'initFetchOn',
|
||||
autoComplete: false,
|
||||
visibleOn: 'typeof this.initFetch !== "boolean"',
|
||||
type: 'input-text',
|
||||
mode: 'normal',
|
||||
size: 'lg',
|
||||
renderLabel: false,
|
||||
placeholder: '如:this.id 表示有 id 值时初始加载',
|
||||
className: 'm-t-n-sm'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '定时刷新',
|
||||
name: 'interval',
|
||||
type: 'switch',
|
||||
mode: 'horizontal',
|
||||
visibleOn: 'data.initApi',
|
||||
pipeIn: (value: any) => !!value,
|
||||
pipeOut: (value: any) => (value ? 3000 : undefined)
|
||||
},
|
||||
{
|
||||
label: '',
|
||||
name: 'interval',
|
||||
@ -563,13 +644,6 @@ export default class APIControl extends React.Component<
|
||||
size: 'lg',
|
||||
visibleOn: '!!data.interval',
|
||||
placeholder: '停止定时刷新检测表达式'
|
||||
// labelRemark: {
|
||||
// trigger: 'hover',
|
||||
// rootClose: true,
|
||||
// content:
|
||||
// '定时刷新一旦设置会一直刷新,除非给出表达式,条件满足后则停止刷新',
|
||||
// placement: 'top'
|
||||
// }
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -589,13 +663,6 @@ export default class APIControl extends React.Component<
|
||||
),
|
||||
name: 'data',
|
||||
mode: 'row',
|
||||
// labelRemark: {
|
||||
// trigger: 'hover',
|
||||
// rootClose: true,
|
||||
// content:
|
||||
// '当没开启数据映射时,发送 API 的时候会发送尽可能多的数据,如果你想自己控制发送的数据,或者需要额外的数据处理,请开启此选项',
|
||||
// placement: 'top'
|
||||
// },
|
||||
pipeIn: (value: any) => !!value,
|
||||
pipeOut: (value: any) => (value ? {'&': '$$'} : null)
|
||||
},
|
||||
@ -656,7 +723,7 @@ export default class APIControl extends React.Component<
|
||||
|
||||
{
|
||||
placeholder: 'Value',
|
||||
type: 'input-text',
|
||||
type: 'ae-DataPickerControl',
|
||||
name: 'value'
|
||||
}
|
||||
]
|
||||
@ -669,13 +736,6 @@ export default class APIControl extends React.Component<
|
||||
),
|
||||
name: 'responseData',
|
||||
mode: 'row',
|
||||
// labelRemark: {
|
||||
// trigger: 'hover',
|
||||
// rootClose: true,
|
||||
// content:
|
||||
// '如果需要对返回结果做额外的数据处理,请开启此选项',
|
||||
// placement: 'top'
|
||||
// },
|
||||
pipeIn: (value: any) => !!value,
|
||||
pipeOut: (value: any) => (value ? {'&': '$$'} : null)
|
||||
},
|
||||
@ -772,18 +832,11 @@ export default class APIControl extends React.Component<
|
||||
type: 'switch',
|
||||
label: tipedLabel(
|
||||
'请求头',
|
||||
'可以配置headers对象,添加自定义请求头'
|
||||
'可以配置<code>headers</code>对象,添加自定义请求头'
|
||||
),
|
||||
name: 'headers',
|
||||
mode: 'row',
|
||||
className: 'm-b-xs',
|
||||
// labelRemark: {
|
||||
// trigger: 'hover',
|
||||
// rootClose: true,
|
||||
// content:
|
||||
// '可以配置<code>headers</code>对象,添加自定义请求头',
|
||||
// placement: 'top'
|
||||
// },
|
||||
pipeIn: (value: any) => !!value,
|
||||
pipeOut: (value: any) => (value ? {'': ''} : null)
|
||||
},
|
||||
@ -915,42 +968,103 @@ export default class APIControl extends React.Component<
|
||||
}
|
||||
]
|
||||
};
|
||||
// return
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
render,
|
||||
className,
|
||||
footerClassName,
|
||||
classPrefix,
|
||||
label,
|
||||
labelRemark,
|
||||
value,
|
||||
footer,
|
||||
border = false,
|
||||
messageDesc
|
||||
onlyTabs = false,
|
||||
messageDesc,
|
||||
enablePickerMode,
|
||||
disabled,
|
||||
mode,
|
||||
enableHighlight,
|
||||
labelField = 'label',
|
||||
useMobileUI,
|
||||
popOverContainer,
|
||||
env
|
||||
} = this.props;
|
||||
let {apiStr, selectedItem, loading} = this.state;
|
||||
selectedItem =
|
||||
Array.isArray(selectedItem) && selectedItem.length !== 0
|
||||
? selectedItem
|
||||
: [];
|
||||
const highlightLabel = selectedItem?.[0]?.[labelField] ?? '';
|
||||
|
||||
return (
|
||||
<div className={cx('ae-ApiControl', className, {border})}>
|
||||
{this.renderHeader()}
|
||||
<>
|
||||
<div className={cx('ae-ApiControl', className, {border})}>
|
||||
{onlyTabs ? (
|
||||
render('api-control-tabs', this.renderApiConfigTabs(true), {
|
||||
data: normalizeApi(value)
|
||||
})
|
||||
) : (
|
||||
<>
|
||||
{this.renderHeader()}
|
||||
|
||||
<div className="ae-ApiControl-content" key="content">
|
||||
<InputBox
|
||||
className="ae-ApiControl-input m-b-none"
|
||||
value={this.state.apiStr}
|
||||
clearable={false}
|
||||
placeholder="http://"
|
||||
onChange={(value: string) => this.handleSubmit(value, 'input')}
|
||||
/>
|
||||
{render('api-control-dialog', this.renderApiDialog(), {
|
||||
data: normalizeApi(value)
|
||||
})}
|
||||
<div className="ae-ApiControl-content" key="content">
|
||||
<div className={cx('ae-ApiControl-input')}>
|
||||
{enableHighlight && highlightLabel ? (
|
||||
<div className={cx('ae-ApiControl-highlight')}>
|
||||
{loading ? (
|
||||
<Spinner
|
||||
show
|
||||
icon="reload"
|
||||
size="sm"
|
||||
spinnerClassName={cx('Select-spinner')}
|
||||
/>
|
||||
) : (
|
||||
<span className={cx('ae-ApiControl-highlight-tag')}>
|
||||
<span>{highlightLabel}</span>
|
||||
<a
|
||||
onClick={this.clearPickerValue}
|
||||
className={cx('Modal-close')}
|
||||
>
|
||||
<Icon
|
||||
icon="close"
|
||||
className={cx(
|
||||
'icon',
|
||||
'ae-ApiControl-highlight-close'
|
||||
)}
|
||||
/>
|
||||
</a>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<Input
|
||||
ref={this.inputRef}
|
||||
value={apiStr}
|
||||
type="text"
|
||||
disabled={disabled}
|
||||
placeholder="http://"
|
||||
onChange={this.handleSimpleInputChange}
|
||||
/>
|
||||
)}
|
||||
{enablePickerMode ? this.renderPickerSchema() : null}
|
||||
</div>
|
||||
|
||||
{render('api-control-dialog', this.renderApiDialog(), {
|
||||
data: normalizeApi(value)
|
||||
})}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{Array.isArray(footer) && footer.length !== 0 ? (
|
||||
<footer className="mt-3" key="footer">
|
||||
<footer className={cx('mt-3', footerClassName)} key="footer">
|
||||
{render('api-control-footer', footer)}
|
||||
</footer>
|
||||
) : null}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import {getEnv} from 'mobx-state-tree';
|
||||
import {normalizeApi, isEffectiveApi, isApiOutdated} from 'amis-core';
|
||||
|
||||
import {autobind, isObject, anyChanged, createObject} from 'amis-editor-core';
|
||||
import {tipedLabel} from '../component/BaseControl';
|
||||
import {tipedLabel} from 'amis-editor-core';
|
||||
|
||||
import type {SchemaObject, SchemaCollection, SchemaApi} from 'amis/lib/Schema';
|
||||
import type {Api} from 'amis/lib/types';
|
||||
|
73
packages/amis-editor/src/renderer/ColumnControl.tsx
Normal file
73
packages/amis-editor/src/renderer/ColumnControl.tsx
Normal file
@ -0,0 +1,73 @@
|
||||
/**
|
||||
* @file 表格自定义列可视化编辑控件
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import cx from 'classnames';
|
||||
import findIndex from 'lodash/findIndex';
|
||||
import {
|
||||
FormControlProps,
|
||||
FormItem,
|
||||
TreeSelection
|
||||
} from 'amis';
|
||||
|
||||
|
||||
export interface ColumnControlProps extends FormControlProps {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export interface ColumnsControlState {
|
||||
columns: Array<any>;
|
||||
}
|
||||
|
||||
export default class ColumnControl extends React.Component<
|
||||
ColumnControlProps,
|
||||
ColumnsControlState
|
||||
> {
|
||||
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
columns: this.transformColumns(props)
|
||||
};
|
||||
}
|
||||
|
||||
transformColumns(props: any) {
|
||||
const {data} = props;
|
||||
return data.columns;
|
||||
}
|
||||
|
||||
onChange(value: Array<any>) {
|
||||
const {onBulkChange} = this.props;
|
||||
const columns = this.state.columns.map(c => ({
|
||||
...c,
|
||||
toggled: findIndex(value, (v: any) => v.value === c.key) > -1
|
||||
}));
|
||||
|
||||
this.setState({columns});
|
||||
onBulkChange && onBulkChange({columns});
|
||||
}
|
||||
|
||||
render() {
|
||||
const {columns} = this.state;
|
||||
const options = columns ? columns.map(c => ({value: c.key, label: c.title})) : [];
|
||||
const value = columns ? columns.filter(c => c.toggled !== false).map(c => ({value: c.key, label: c.title})) : []
|
||||
|
||||
return (
|
||||
<div className={cx('ae-ColumnControl')}>
|
||||
<TreeSelection
|
||||
options={options}
|
||||
value={value}
|
||||
onChange={(v: Array<any>) => this.onChange(v)}>
|
||||
</TreeSelection>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@FormItem({
|
||||
type: 'ae-columnControl',
|
||||
renderLabel: false
|
||||
})
|
||||
export class ColumnControlRenderer extends ColumnControl {}
|
@ -1,37 +1,244 @@
|
||||
import {Icon, InputBox, SchemaVariableListPicker, FormItem} from 'amis';
|
||||
import type {FormControlProps} from 'amis-core';
|
||||
import {
|
||||
Icon,
|
||||
InputBox,
|
||||
SchemaVariableListPicker,
|
||||
FormItem,
|
||||
SearchBox,
|
||||
CollapseGroup,
|
||||
PickerContainer,
|
||||
Collapse,
|
||||
Checkbox,
|
||||
Spinner
|
||||
} from 'amis';
|
||||
import {FormControlProps, generateIcon} from 'amis-core';
|
||||
import {debounce, remove} from 'lodash';
|
||||
import React from 'react';
|
||||
import {autobind} from 'amis-editor-core';
|
||||
import {
|
||||
EditorManager,
|
||||
EditorNodeType,
|
||||
autobind,
|
||||
DSField,
|
||||
DSFieldGroup
|
||||
} from 'amis-editor-core';
|
||||
import {matchSorter} from 'match-sorter';
|
||||
|
||||
export interface DataBindingProps extends FormControlProps {
|
||||
node: EditorNodeType;
|
||||
manager: EditorManager;
|
||||
samePredicate?: (a: any, b: any) => boolean;
|
||||
onBindingChange?: (
|
||||
value: DSField,
|
||||
onBulkChange: (value: any) => void
|
||||
) => void;
|
||||
}
|
||||
|
||||
export interface DataBindingState {
|
||||
filteredFields: DSFieldGroup[];
|
||||
sourceFields: DSFieldGroup[];
|
||||
loading: boolean;
|
||||
hint: string | void;
|
||||
}
|
||||
|
||||
export class DataBindingControl extends React.Component<
|
||||
DataBindingProps,
|
||||
DataBindingState
|
||||
> {
|
||||
constructor(props: DataBindingProps) {
|
||||
super(props);
|
||||
this.handleSearchDebounced = debounce(this.handleSearch, 250, {
|
||||
trailing: true,
|
||||
leading: false
|
||||
});
|
||||
this.state = {
|
||||
filteredFields: [],
|
||||
sourceFields: [],
|
||||
loading: false,
|
||||
hint: undefined
|
||||
};
|
||||
}
|
||||
|
||||
handleSearchDebounced;
|
||||
|
||||
export class DataBindingControl extends React.Component<FormControlProps> {
|
||||
@autobind
|
||||
handleConfirm(result: {value: string; schema: any}) {
|
||||
const {manager, data} = this.props;
|
||||
handleConfirm(result: {label: string; value: string}) {
|
||||
const {manager, data, onChange, onBulkChange, onBindingChange} = this.props;
|
||||
|
||||
if (result?.value) {
|
||||
this.props.onChange(`${result.value}`);
|
||||
onChange(result.value);
|
||||
onBulkChange && onBindingChange?.(result, onBulkChange);
|
||||
manager.config?.dataBindingChange?.(result.value, data, manager);
|
||||
}
|
||||
}
|
||||
|
||||
@autobind
|
||||
async handlePickerOpen() {
|
||||
handlePickerOpen() {
|
||||
const {manager, node} = this.props;
|
||||
const withSuper = manager.config?.withSuperDataSchema ?? false;
|
||||
const schemas = await manager.getContextSchemas(node.info.id, !withSuper);
|
||||
return {schemas};
|
||||
|
||||
// 如果node没变化,就不再重复加载
|
||||
if (this.state.sourceFields.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
sourceFields: [],
|
||||
filteredFields: [],
|
||||
loading: true
|
||||
});
|
||||
|
||||
manager
|
||||
.getAvailableContextFields(node)
|
||||
.then(groupedFields => {
|
||||
this.setState({
|
||||
sourceFields: groupedFields || [],
|
||||
filteredFields: groupedFields || [],
|
||||
loading: false,
|
||||
hint: groupedFields ? undefined : '暂无可绑定字段'
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
this.setState({
|
||||
loading: false,
|
||||
hint: '加载可用字段失败,请联系管理员!'
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const {classnames: cx, value, onChange, disabled} = this.props;
|
||||
@autobind
|
||||
async handleSearch(keywords: string) {
|
||||
this.setState({
|
||||
filteredFields: matchSorter(this.state.sourceFields, keywords, {
|
||||
keys: ['label', 'value', 'children']
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleSelect() {}
|
||||
|
||||
render() {
|
||||
const {
|
||||
className,
|
||||
classnames: cx,
|
||||
value,
|
||||
onChange,
|
||||
samePredicate = (a, b) => a.value === b.value,
|
||||
multiple,
|
||||
disabled
|
||||
} = this.props;
|
||||
|
||||
const {filteredFields, loading, hint} = this.state;
|
||||
return (
|
||||
<SchemaVariableListPicker
|
||||
<PickerContainer
|
||||
onPickerOpen={this.handlePickerOpen}
|
||||
className={className}
|
||||
title="绑定字段"
|
||||
bodyRender={({value, isOpened, onChange}) => {
|
||||
if (!isOpened) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<Spinner
|
||||
show
|
||||
icon="reload"
|
||||
spinnerClassName={cx('ae-DataBindingList-spinner')}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (hint) {
|
||||
return <p className={cx('ae-DataBindingList-hint')}>{hint}</p>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cx('ae-DataBindingList')}>
|
||||
<div className={cx('ae-DataBindingList-searchBox')}>
|
||||
<SearchBox
|
||||
mini={false}
|
||||
placeholder={'输入名称搜索'}
|
||||
onSearch={this.handleSearchDebounced}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={cx('ae-DataBindingList-body')}>
|
||||
<CollapseGroup
|
||||
className={cx('ae-DataBindingList-collapseGroup')}
|
||||
defaultActiveKey={filteredFields.map(item => item.value!)}
|
||||
expandIcon={
|
||||
generateIcon(
|
||||
cx,
|
||||
'fa fa-chevron-right ae-DataBindingList-expandIcon',
|
||||
'Icon'
|
||||
)!
|
||||
}
|
||||
expandIconPosition="right"
|
||||
// accordion={true}
|
||||
>
|
||||
{filteredFields.map(item => (
|
||||
<Collapse
|
||||
className={cx('ae-DataBindingList-collapse')}
|
||||
headingClassName={cx('ae-DataBindingList-collapse-title')}
|
||||
bodyClassName={cx('ae-DataBindingList-collapse-body')}
|
||||
propKey={item.value}
|
||||
key={item.value}
|
||||
header={item.label}
|
||||
>
|
||||
{Array.isArray(item.children) &&
|
||||
item.children.length > 0 ? (
|
||||
item.children.map((childItem: DSField) => {
|
||||
if (multiple) {
|
||||
const checked = !!value.find((i: any) =>
|
||||
samePredicate(i, childItem)
|
||||
);
|
||||
return (
|
||||
<div
|
||||
key={childItem.value}
|
||||
className={cx('ae-DataBindingList-item')}
|
||||
onClick={() =>
|
||||
onChange(
|
||||
checked
|
||||
? value.concat(childItem)
|
||||
: remove(value, childItem)
|
||||
)
|
||||
}
|
||||
>
|
||||
<Checkbox value={checked}>
|
||||
{childItem.label}
|
||||
</Checkbox>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cx('ae-DataBindingList-item', {
|
||||
'is-active':
|
||||
value && childItem.value === value.value
|
||||
})}
|
||||
onClick={() => onChange(childItem)}
|
||||
key={childItem.value}
|
||||
>
|
||||
{childItem.label}
|
||||
</div>
|
||||
);
|
||||
})
|
||||
) : (
|
||||
<p className={cx('ae-DataBindingList-hint')}>
|
||||
暂无可用字段
|
||||
</p>
|
||||
)}
|
||||
</Collapse>
|
||||
))}
|
||||
</CollapseGroup>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
value={value}
|
||||
onConfirm={this.handleConfirm}
|
||||
title="绑定变量"
|
||||
>
|
||||
{({onClick, isOpened, setState}) => {
|
||||
{({onClick}: {onClick: (e: React.MouseEvent) => void}) => {
|
||||
return (
|
||||
<InputBox
|
||||
className="ae-InputVariable"
|
||||
@ -50,7 +257,7 @@ export class DataBindingControl extends React.Component<FormControlProps> {
|
||||
</InputBox>
|
||||
);
|
||||
}}
|
||||
</SchemaVariableListPicker>
|
||||
</PickerContainer>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -47,7 +47,9 @@ class DataPickerControl extends React.Component<FormControlProps> {
|
||||
onChange={() => {}}
|
||||
header={''}
|
||||
>
|
||||
{({onClick, isOpened, setState}) => {
|
||||
{({onClick}: {
|
||||
onClick: (e: React.MouseEvent) => void;
|
||||
}) => {
|
||||
return (
|
||||
<InputBox
|
||||
className="ae-InputVariable"
|
||||
|
268
packages/amis-editor/src/renderer/FeatureControl.tsx
Normal file
268
packages/amis-editor/src/renderer/FeatureControl.tsx
Normal file
@ -0,0 +1,268 @@
|
||||
/**
|
||||
* @file 控制功能开关的控件,这里的功能指需要加子组件来支持的功能
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import {findDOMNode} from 'react-dom';
|
||||
import cx from 'classnames';
|
||||
import {FormItem, Button, Icon, FormControlProps, autobind} from 'amis';
|
||||
|
||||
import {clone, remove} from 'lodash';
|
||||
import {GoConfigControl} from './GoConfigControl';
|
||||
import Sortable from 'sortablejs';
|
||||
|
||||
const klass = 'ae-FeatureControl';
|
||||
export type FeatureOption = {
|
||||
label: string;
|
||||
value: any;
|
||||
remove?: (data: any) => void;
|
||||
/** 提供该字段表示删除后还可以再新增回来 */
|
||||
add?: (data: any) => void;
|
||||
isActive?: (data: any) => boolean;
|
||||
};
|
||||
|
||||
interface FeatureControlProps extends FormControlProps {
|
||||
className?: string;
|
||||
removable?: boolean;
|
||||
addable?: boolean;
|
||||
addText?: string;
|
||||
sortable?: boolean;
|
||||
features: Array<FeatureOption> | ((schema: any) => Array<FeatureOption>);
|
||||
goFeatureComp?: (item: FeatureOption) => string; // 去子组件
|
||||
onSort?: (value: FeatureOption[]) => void;
|
||||
}
|
||||
|
||||
interface FeatureControlState {
|
||||
/**
|
||||
* 当前启用的功能
|
||||
*/
|
||||
inUseFeat: FeatureOption[];
|
||||
|
||||
/**
|
||||
* 未启用的功能
|
||||
*/
|
||||
unUseFeat: FeatureOption[];
|
||||
}
|
||||
|
||||
export default class FeatureControl extends React.Component<
|
||||
FeatureControlProps,
|
||||
FeatureControlState
|
||||
> {
|
||||
constructor(props: FeatureControlProps) {
|
||||
super(props);
|
||||
this.state = FeatureControl.initState(props.data, props.features);
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps(
|
||||
nextProps: FeatureControlProps,
|
||||
preState: FeatureControlState
|
||||
) {
|
||||
return FeatureControl.initState(
|
||||
nextProps.data,
|
||||
nextProps.features,
|
||||
preState.inUseFeat,
|
||||
preState.unUseFeat
|
||||
);
|
||||
}
|
||||
|
||||
static initState(
|
||||
data: any,
|
||||
features: FeatureOption[] | ((schema: any) => Array<FeatureOption>),
|
||||
lastInUseFeat?: FeatureOption[],
|
||||
lastUnUseFeat?: FeatureOption[]
|
||||
) {
|
||||
const inUseFeat: FeatureOption[] = [];
|
||||
const unUseFeat: FeatureOption[] = [];
|
||||
|
||||
if (!Array.isArray(features)) {
|
||||
features = features(data);
|
||||
}
|
||||
|
||||
features.forEach(item => {
|
||||
if (item.isActive == null || item.isActive?.(data)) {
|
||||
inUseFeat.push(item);
|
||||
} else if (item.add) {
|
||||
unUseFeat.push(item);
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
inUseFeat,
|
||||
unUseFeat
|
||||
};
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleRemove(item: FeatureOption, index: number) {
|
||||
const {removeFeature, data, onBulkChange} = this.props;
|
||||
const {inUseFeat, unUseFeat} = this.state;
|
||||
|
||||
item.remove?.(data);
|
||||
removeFeature?.(item, data);
|
||||
onBulkChange?.(data);
|
||||
|
||||
remove(inUseFeat, item);
|
||||
item.add && unUseFeat.push(item);
|
||||
|
||||
this.setState({inUseFeat, unUseFeat});
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleAdd(item: any) {
|
||||
const {addFeature, data, onBulkChange} = this.props;
|
||||
const {inUseFeat, unUseFeat} = this.state;
|
||||
|
||||
inUseFeat.push(item);
|
||||
remove(unUseFeat, item);
|
||||
|
||||
const schema = clone(data);
|
||||
item.add?.(schema);
|
||||
addFeature?.(item, schema);
|
||||
onBulkChange?.(schema);
|
||||
}
|
||||
|
||||
sortable?: Sortable;
|
||||
drag?: HTMLElement | null;
|
||||
@autobind
|
||||
dragRef(ref: any) {
|
||||
const {sortable} = this.props;
|
||||
if (!sortable) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.drag && ref) {
|
||||
this.initDragging();
|
||||
} else if (this.drag && !ref) {
|
||||
this.destroyDragging();
|
||||
}
|
||||
|
||||
this.drag = ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化拖动
|
||||
*/
|
||||
initDragging() {
|
||||
const dom = findDOMNode(this) as HTMLElement;
|
||||
this.sortable = new Sortable(
|
||||
dom.querySelector(`.${klass}-features`) as HTMLElement,
|
||||
{
|
||||
group: 'FeatureControlGroup',
|
||||
animation: 150,
|
||||
handle: `.${klass}Item-dragBar`,
|
||||
ghostClass: `${klass}Item-dragging`,
|
||||
onEnd: (e: any) => {
|
||||
// 没有移动
|
||||
if (e.newIndex === e.oldIndex) {
|
||||
return;
|
||||
}
|
||||
// 换回来
|
||||
const parent = e.to as HTMLElement;
|
||||
if (
|
||||
e.newIndex < e.oldIndex &&
|
||||
e.oldIndex < parent.childNodes.length - 1
|
||||
) {
|
||||
parent.insertBefore(e.item, parent.childNodes[e.oldIndex + 1]);
|
||||
} else if (e.oldIndex < parent.childNodes.length - 1) {
|
||||
parent.insertBefore(e.item, parent.childNodes[e.oldIndex]);
|
||||
} else {
|
||||
parent.appendChild(e.item);
|
||||
}
|
||||
|
||||
const value = this.state.inUseFeat.concat();
|
||||
value[e.oldIndex] = value.splice(e.newIndex, 1, value[e.oldIndex])[0];
|
||||
this.setState({inUseFeat: value}, () => {
|
||||
this.props.onSort?.(value);
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 拖动的销毁
|
||||
*/
|
||||
destroyDragging() {
|
||||
this.sortable && this.sortable.destroy();
|
||||
}
|
||||
|
||||
renderItem(item: FeatureOption, index: number) {
|
||||
const {sortable, goFeatureComp, node, manager} = this.props;
|
||||
|
||||
let content = null;
|
||||
|
||||
if (goFeatureComp) {
|
||||
content = (
|
||||
// @ts-ignore
|
||||
<GoConfigControl
|
||||
className={cx(`${klass}Item-go`)}
|
||||
label={item.label}
|
||||
manager={manager}
|
||||
compId={() => goFeatureComp(item)}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
content = <div className={cx(`${klass}Item-label`)}>{item.label}</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<li className={klass + 'Item'} key={index}>
|
||||
{sortable && (
|
||||
<a className={klass + 'Item-dragBar'}>
|
||||
<Icon icon="drag-bar" className="icon" />
|
||||
</a>
|
||||
)}
|
||||
{content}
|
||||
<Button
|
||||
className={klass + 'Item-action'}
|
||||
onClick={() => this.handleRemove(item, index)}
|
||||
>
|
||||
<Icon icon="delete-btn" className="icon" />
|
||||
</Button>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
renderAction() {
|
||||
const {addable, addText, render} = this.props;
|
||||
if (!addable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return render('action', {
|
||||
type: 'dropdown-button',
|
||||
closeOnClick: true,
|
||||
label: '添加' || addText,
|
||||
className: `${klass}-action`,
|
||||
btnClassName: `${klass}-action--btn`,
|
||||
menuClassName: `${klass}-action--menus`,
|
||||
buttons: this.state.unUseFeat.map(item => {
|
||||
return {
|
||||
label: item.label,
|
||||
onClick: () => this.handleAdd(item)
|
||||
};
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const {className} = this.props;
|
||||
|
||||
return (
|
||||
<div className={cx('ae-FeatureControl', className)}>
|
||||
<ul className={cx('ae-FeatureControl-features')} ref={this.dragRef}>
|
||||
{this.state.inUseFeat.map((item, index) =>
|
||||
this.renderItem(item, index)
|
||||
)}
|
||||
</ul>
|
||||
|
||||
{this.renderAction()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@FormItem({
|
||||
type: 'ae-feature-control'
|
||||
})
|
||||
export class FeatureControlRenderer extends FeatureControl {}
|
@ -248,7 +248,14 @@ export default class FormulaControl extends React.Component<
|
||||
const {node, manager} = this.props.formProps || this.props;
|
||||
await manager?.getContextSchemas(node);
|
||||
const dataPropsAsOptions = manager?.dataSchema?.getDataPropsAsOptions();
|
||||
return dataPropsAsOptions || [];
|
||||
|
||||
if (dataPropsAsOptions) {
|
||||
return dataPropsAsOptions.map((item: any) => ({
|
||||
selectMode: 'tree',
|
||||
...item
|
||||
}));
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
@autobind
|
||||
@ -331,9 +338,7 @@ export default class FormulaControl extends React.Component<
|
||||
@autobind
|
||||
renderFormulaValue(item: any) {
|
||||
const html = {__html: item.html};
|
||||
{
|
||||
/* bca-disable-next-line */
|
||||
}
|
||||
// bca-disable-line
|
||||
return <span dangerouslySetInnerHTML={html}></span>;
|
||||
}
|
||||
|
||||
@ -452,7 +457,13 @@ export default class FormulaControl extends React.Component<
|
||||
)}
|
||||
<PickerContainer
|
||||
showTitle={false}
|
||||
bodyRender={({onClose, value, onChange}) => {
|
||||
bodyRender={({
|
||||
value,
|
||||
onChange
|
||||
}: {
|
||||
onChange: (value: any) => void;
|
||||
value: any;
|
||||
}) => {
|
||||
return (
|
||||
<FormulaEditor
|
||||
{...rest}
|
||||
@ -470,7 +481,7 @@ export default class FormulaControl extends React.Component<
|
||||
onConfirm={this.handleConfirm}
|
||||
size="md"
|
||||
>
|
||||
{({onClick, isOpened}) => (
|
||||
{({onClick}: {onClick: (e: React.MouseEvent) => void}) => (
|
||||
<Button
|
||||
size="sm"
|
||||
tooltip={'点击配置表达式'}
|
||||
|
49
packages/amis-editor/src/renderer/GoConfigControl.tsx
Normal file
49
packages/amis-editor/src/renderer/GoConfigControl.tsx
Normal file
@ -0,0 +1,49 @@
|
||||
/**
|
||||
* @file 进行详细配置
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import cx from 'classnames';
|
||||
import {Renderer, toast} from 'amis';
|
||||
|
||||
import {EditorManager} from 'amis-editor-core';
|
||||
import {autobind, FormControlProps} from 'amis-core';
|
||||
|
||||
export interface GoCongigControlProps extends FormControlProps {
|
||||
label: string;
|
||||
compId: string | ((data: any) => string);
|
||||
manager: EditorManager;
|
||||
}
|
||||
|
||||
export class GoConfigControl extends React.PureComponent<
|
||||
GoCongigControlProps,
|
||||
any
|
||||
> {
|
||||
@autobind
|
||||
onClick() {
|
||||
const {data: ctx = {}, compId, manager} = this.props;
|
||||
const id = typeof compId === 'string' ? compId : compId(ctx);
|
||||
|
||||
if (!id) {
|
||||
toast.error('未找到对应组件');
|
||||
return;
|
||||
}
|
||||
manager.setActiveId(id);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {className, label, data: ctx = {}} = this.props;
|
||||
|
||||
return (
|
||||
<div className={cx('ae-GoConfig', className)} onClick={this.onClick}>
|
||||
{label}
|
||||
<div className={cx('ae-GoConfig-trigger')}>去编辑</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Renderer({
|
||||
type: 'ae-go-config'
|
||||
})
|
||||
export class GoConfigControlRenderer extends GoConfigControl {}
|
@ -20,7 +20,7 @@ import {value2array} from 'amis-ui/lib/components/Select';
|
||||
|
||||
import {autobind} from 'amis-editor-core';
|
||||
import {getSchemaTpl} from 'amis-editor-core';
|
||||
import {tipedLabel} from '../component/BaseControl';
|
||||
import {tipedLabel} from 'amis-editor-core';
|
||||
|
||||
import type {Option} from 'amis';
|
||||
import type {FormControlProps} from 'amis-core';
|
||||
@ -396,33 +396,29 @@ export default class OptionControl extends React.Component<
|
||||
}
|
||||
|
||||
renderHeader() {
|
||||
const {
|
||||
render,
|
||||
label,
|
||||
labelRemark,
|
||||
useMobileUI,
|
||||
env,
|
||||
popOverContainer
|
||||
} = this.props;
|
||||
const {render, label, labelRemark, useMobileUI, env, popOverContainer} =
|
||||
this.props;
|
||||
const classPrefix = env?.theme?.classPrefix;
|
||||
const {source} = this.state;
|
||||
const optionSourceList = ([
|
||||
{
|
||||
label: '自定义选项',
|
||||
value: 'custom'
|
||||
},
|
||||
{
|
||||
label: '接口获取',
|
||||
value: 'api'
|
||||
}
|
||||
// {
|
||||
// label: '表单实体',
|
||||
// value: 'form'
|
||||
// }
|
||||
] as Array<{
|
||||
label: string;
|
||||
value: 'custom' | 'api' | 'form';
|
||||
}>).map(item => ({
|
||||
const optionSourceList = (
|
||||
[
|
||||
{
|
||||
label: '自定义选项',
|
||||
value: 'custom'
|
||||
},
|
||||
{
|
||||
label: '接口获取',
|
||||
value: 'api'
|
||||
}
|
||||
// {
|
||||
// label: '表单实体',
|
||||
// value: 'form'
|
||||
// }
|
||||
] as Array<{
|
||||
label: string;
|
||||
value: 'custom' | 'api' | 'form';
|
||||
}>
|
||||
).map(item => ({
|
||||
...item,
|
||||
onClick: () => this.handleSourceChange(item.value)
|
||||
}));
|
||||
@ -586,7 +582,7 @@ export default class OptionControl extends React.Component<
|
||||
value={label}
|
||||
placeholder="请输入文本/值"
|
||||
clearable={false}
|
||||
onChange={value => this.handleEditLabel(index, value)}
|
||||
onChange={(value: string) => this.handleEditLabel(index, value)}
|
||||
/>
|
||||
{amisRender({
|
||||
type: 'dropdown-button',
|
||||
@ -636,8 +632,7 @@ export default class OptionControl extends React.Component<
|
||||
body: [
|
||||
{
|
||||
type: 'tpl',
|
||||
tpl:
|
||||
'每个选项单列一行,将所有值不重复的项加为新的选项;<br/>每行可通过空格来分别设置label和value,例:"张三 zhangsan"'
|
||||
tpl: '每个选项单列一行,将所有值不重复的项加为新的选项;<br/>每行可通过空格来分别设置label和value,例:"张三 zhangsan"'
|
||||
}
|
||||
],
|
||||
showIcon: true,
|
||||
@ -700,6 +695,7 @@ export default class OptionControl extends React.Component<
|
||||
getSchemaTpl('apiControl', {
|
||||
label: '接口',
|
||||
name: 'source',
|
||||
mode: 'normal',
|
||||
className: 'ae-ExtendMore',
|
||||
visibleOn: 'data.autoComplete !== false',
|
||||
value: api,
|
||||
|
@ -1,277 +0,0 @@
|
||||
/**
|
||||
* @file 浮窗编辑
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import {findDOMNode} from 'react-dom';
|
||||
import cx from 'classnames';
|
||||
import {FormItem, Button, Overlay, PopOver, Icon, Switch} from 'amis';
|
||||
|
||||
import {isObject, autobind} from 'amis-editor-core';
|
||||
|
||||
import type {Action} from 'amis/lib/types';
|
||||
import type {IScopedContext} from 'amis-core';
|
||||
|
||||
import type {FormControlProps} from 'amis-core';
|
||||
import type {FormSchema} from 'amis/lib/Schema';
|
||||
import {Offset} from 'amis-core/lib/components/PopOver';
|
||||
|
||||
export interface PopoverEditProps extends FormControlProps {
|
||||
className?: string;
|
||||
popOverclassName?: string;
|
||||
btnLabel?: string;
|
||||
btnIcon?: string;
|
||||
iconPosition?: 'right' | 'left';
|
||||
mode: 'popover' | 'dialog';
|
||||
form: Omit<FormSchema, 'type'>;
|
||||
rootClose?: boolean;
|
||||
placement?: string;
|
||||
offset?: ((clip: object, offset: object) => Offset) | Offset;
|
||||
style?: object;
|
||||
overlay?: boolean;
|
||||
container?: React.ReactNode | Function;
|
||||
target?: React.ReactNode | Function;
|
||||
trueValue?: any;
|
||||
falseValue?: any;
|
||||
enableEdit?: boolean;
|
||||
removable?: boolean;
|
||||
onClose: (e: React.UIEvent<any> | void) => void;
|
||||
}
|
||||
|
||||
interface PopoverEditState {
|
||||
/**
|
||||
* 是否展示编辑窗口
|
||||
*/
|
||||
show: boolean;
|
||||
|
||||
/**
|
||||
* 是否开启编辑
|
||||
*/
|
||||
checked: boolean;
|
||||
}
|
||||
|
||||
export class PopoverEdit extends React.Component<
|
||||
PopoverEditProps,
|
||||
PopoverEditState
|
||||
> {
|
||||
static defaultProps: Pick<
|
||||
PopoverEditProps,
|
||||
| 'btnIcon'
|
||||
| 'iconPosition'
|
||||
| 'container'
|
||||
| 'placement'
|
||||
| 'overlay'
|
||||
| 'rootClose'
|
||||
| 'mode'
|
||||
| 'trueValue'
|
||||
| 'falseValue'
|
||||
| 'enableEdit'
|
||||
> = {
|
||||
btnIcon: 'pencil',
|
||||
iconPosition: 'right',
|
||||
container: document.body,
|
||||
placement: 'left',
|
||||
overlay: true,
|
||||
rootClose: false,
|
||||
mode: 'popover',
|
||||
trueValue: true,
|
||||
falseValue: false,
|
||||
enableEdit: true
|
||||
};
|
||||
|
||||
overlay: HTMLElement | null;
|
||||
|
||||
constructor(props: PopoverEditProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
show: false,
|
||||
checked: !!props.value
|
||||
};
|
||||
}
|
||||
|
||||
@autobind
|
||||
overlayRef(ref: any) {
|
||||
this.overlay = ref ? (findDOMNode(ref) as HTMLElement) : null;
|
||||
}
|
||||
|
||||
@autobind
|
||||
openPopover() {
|
||||
this.setState({show: true});
|
||||
}
|
||||
|
||||
@autobind
|
||||
closePopover() {
|
||||
this.setState({show: false});
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleDelete(e: React.UIEvent<any> | void) {
|
||||
const {onDelete} = this.props;
|
||||
|
||||
onDelete && onDelete(e);
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleSwitchChange(checked: boolean) {
|
||||
const {onChange, enableEdit} = this.props;
|
||||
|
||||
this.setState({checked});
|
||||
|
||||
if (!enableEdit) {
|
||||
onChange && onChange(checked);
|
||||
} else {
|
||||
// undefined字段会从schema中删除
|
||||
!checked && onChange && onChange(undefined);
|
||||
}
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleSubmit(values: any, action: any) {
|
||||
const {onChange} = this.props;
|
||||
|
||||
onChange && onChange(values);
|
||||
}
|
||||
|
||||
@autobind
|
||||
handleAction(
|
||||
e: React.UIEvent<any> | void,
|
||||
action: Action,
|
||||
data: object,
|
||||
throwErrors: boolean = false,
|
||||
delegate?: IScopedContext
|
||||
) {
|
||||
const {onClose} = this.props;
|
||||
|
||||
if (action.actionType === 'close') {
|
||||
this.setState({show: false});
|
||||
onClose && onClose(e);
|
||||
}
|
||||
}
|
||||
|
||||
renderPopover() {
|
||||
const {
|
||||
render,
|
||||
popOverclassName,
|
||||
overlay,
|
||||
offset,
|
||||
target,
|
||||
container,
|
||||
placement,
|
||||
rootClose,
|
||||
style,
|
||||
title,
|
||||
label,
|
||||
form,
|
||||
name,
|
||||
data: ctx
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<Overlay
|
||||
show
|
||||
rootClose={rootClose}
|
||||
placement={placement}
|
||||
target={target || this.overlay}
|
||||
container={container}
|
||||
>
|
||||
<PopOver
|
||||
className={cx('ae-PopoverEdit-popover', popOverclassName)}
|
||||
placement={placement}
|
||||
overlay={overlay}
|
||||
offset={offset}
|
||||
style={style}
|
||||
>
|
||||
<header>
|
||||
<p className="ae-PopoverEdit-title">{title || label}</p>
|
||||
<a onClick={this.closePopover} className="ae-PopoverEdit-close">
|
||||
<Icon icon="close" className="icon" />
|
||||
</a>
|
||||
</header>
|
||||
{isObject(form)
|
||||
? render(
|
||||
'popover-edit-form',
|
||||
{
|
||||
type: 'form',
|
||||
wrapWithPanel: false,
|
||||
panelClassName: 'border-none shadow-none mb-0',
|
||||
bodyClassName: 'p-none',
|
||||
actionsClassName: 'border-none mt-2.5',
|
||||
wrapperComponent: 'div',
|
||||
mode: 'horizontal',
|
||||
autoFocus: true,
|
||||
formLazyChange: true,
|
||||
preventEnterSubmit: true,
|
||||
submitOnChange: true,
|
||||
data: ctx && name ? ctx?.[name] : {},
|
||||
...form
|
||||
},
|
||||
{
|
||||
onSubmit: this.handleSubmit
|
||||
}
|
||||
)
|
||||
: null}
|
||||
</PopOver>
|
||||
</Overlay>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
render,
|
||||
removable,
|
||||
btnIcon,
|
||||
btnLabel,
|
||||
iconPosition,
|
||||
disabled,
|
||||
enableEdit,
|
||||
className
|
||||
} = this.props;
|
||||
const {show, checked} = this.state;
|
||||
const btnLabelNode = btnLabel ? <span>{btnLabel}</span> : null;
|
||||
|
||||
return (
|
||||
<div className={cx('ae-PopoverEditControl', className)}>
|
||||
{enableEdit && checked && !disabled ? (
|
||||
<Button
|
||||
level="link"
|
||||
size="sm"
|
||||
ref={this.overlayRef}
|
||||
onClick={this.openPopover}
|
||||
>
|
||||
{iconPosition === 'right' ? (
|
||||
<>
|
||||
{btnLabelNode}
|
||||
<Icon icon={btnIcon} className="icon" />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Icon icon={btnIcon} className="icon" />
|
||||
{btnLabelNode}
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
) : null}
|
||||
|
||||
{removable ? (
|
||||
<Button level="link" size="sm" onClick={this.handleDelete}>
|
||||
<Icon icon="delete-btn" className="icon" />
|
||||
</Button>
|
||||
) : null}
|
||||
|
||||
<Switch
|
||||
value={checked}
|
||||
onChange={this.handleSwitchChange}
|
||||
disabled={disabled}
|
||||
/>
|
||||
|
||||
{show ? this.renderPopover() : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@FormItem({
|
||||
type: 'popover-edit'
|
||||
})
|
||||
export class PopoverEditRenderer extends PopoverEdit {}
|
@ -169,7 +169,7 @@ export default class SwitchMore extends React.Component<
|
||||
|
||||
@autobind
|
||||
handleSwitchChange(checked: boolean) {
|
||||
const {onBulkChange, onChange, bulk, defaultData, name} = this.props;
|
||||
const {onBulkChange, onChange, bulk, defaultData, name, pipeOut} = this.props;
|
||||
|
||||
this.setState({checked});
|
||||
|
||||
@ -179,19 +179,30 @@ export default class SwitchMore extends React.Component<
|
||||
if (checked) {
|
||||
let data = defaultData ? {...defaultData} : {};
|
||||
name && (data[name] = true);
|
||||
if (pipeOut) {
|
||||
data = pipeOut(data);
|
||||
}
|
||||
onBulkChange && onBulkChange(data);
|
||||
}
|
||||
// 取消选中后,讲所有字段重置
|
||||
else {
|
||||
const values = fromPairs(
|
||||
let values = fromPairs(
|
||||
this.getFormItemNames().map(i => [i, undefined])
|
||||
);
|
||||
name && (values[name] = false);
|
||||
if (pipeOut) {
|
||||
values = pipeOut(values);
|
||||
}
|
||||
onBulkChange && onBulkChange(values);
|
||||
}
|
||||
return;
|
||||
}
|
||||
onChange(checked ? defaultData || true : undefined);
|
||||
|
||||
let data = checked ? defaultData || true : undefined;
|
||||
if (pipeOut) {
|
||||
data = pipeOut(data);
|
||||
}
|
||||
onChange(data);
|
||||
}
|
||||
|
||||
@autobind
|
||||
|
@ -8,7 +8,7 @@ import {render, Button, Switch} from 'amis';
|
||||
|
||||
import {autobind} from 'amis-editor-core';
|
||||
import {Validator} from '../validator';
|
||||
import {tipedLabel} from '../component/BaseControl';
|
||||
import {tipedLabel} from 'amis-editor-core';
|
||||
import {SchemaCollection} from 'amis/lib/Schema';
|
||||
|
||||
export type ValidatorData = {
|
||||
|
@ -1,9 +1,11 @@
|
||||
import {setSchemaTpl, getSchemaTpl} from 'amis-editor-core';
|
||||
import {setSchemaTpl, getSchemaTpl, tipedLabel} from 'amis-editor-core';
|
||||
import React from 'react';
|
||||
import {buildApi, Html} from 'amis';
|
||||
import {get} from 'lodash';
|
||||
|
||||
setSchemaTpl('api', (patch: any = {}) => {
|
||||
const {name, label, value, description, sampleBuilder, ...rest} = patch;
|
||||
const {name, label, value, description, sampleBuilder, apiDesc, ...rest} =
|
||||
patch;
|
||||
|
||||
return {
|
||||
type: 'container',
|
||||
@ -13,21 +15,25 @@ setSchemaTpl('api', (patch: any = {}) => {
|
||||
label: label || 'API',
|
||||
labelRemark: sampleBuilder
|
||||
? {
|
||||
icon: '',
|
||||
label: '示例',
|
||||
label: false,
|
||||
title: '接口返回示例',
|
||||
icon: 'fas fa-code',
|
||||
className: 'm-l-xs ae-ApiSample-icon',
|
||||
tooltipClassName: 'ae-ApiSample-tooltip',
|
||||
render: (data: any) => (
|
||||
<Html
|
||||
className="ae-ApiSample"
|
||||
inline={false}
|
||||
html={`
|
||||
<pre><code>${sampleBuilder(data)}</code></pre>
|
||||
`}
|
||||
/>
|
||||
),
|
||||
children: () => {
|
||||
return (
|
||||
<Html
|
||||
className="ae-ApiSample"
|
||||
inline={false}
|
||||
html={`<pre><code>${sampleBuilder()}</code></pre>${
|
||||
apiDesc
|
||||
? `<span class="ae-ApiSample-desc">${apiDesc}</span>`
|
||||
: ''
|
||||
}`}
|
||||
/>
|
||||
);
|
||||
},
|
||||
trigger: 'click',
|
||||
className: 'm-l-xs',
|
||||
rootClose: true,
|
||||
placement: 'left'
|
||||
}
|
||||
@ -166,6 +172,7 @@ setSchemaTpl('api', (patch: any = {}) => {
|
||||
mode: 'normal',
|
||||
renderLabel: false,
|
||||
visibleOn: 'this.data',
|
||||
valueType: 'ae-DataPickerControl',
|
||||
descriptionClassName: 'help-block text-xs m-b-none',
|
||||
description:
|
||||
'<p>当没开启数据映射时,发送数据自动切成白名单模式,配置啥发送啥,请绑定数据。如:<code>{"a": "\\${a}", "b": 2}</code></p><p>如果希望在默认的基础上定制,请先添加一个 Key 为 `&` Value 为 `\\$$` 作为第一行。</p><div>当值为 <code>__undefined</code>时,表示删除对应的字段,可以结合<code>{"&": "\\$$"}</code>来达到黑名单效果。</div>'
|
||||
@ -346,55 +353,66 @@ setSchemaTpl('apiString', {
|
||||
placeholder: 'http://'
|
||||
});
|
||||
|
||||
setSchemaTpl('initFetch', {
|
||||
type: 'group',
|
||||
label: '是否初始加载',
|
||||
visibleOn: 'this.initApi',
|
||||
direction: 'vertical',
|
||||
className: 'm-b-none',
|
||||
labelRemark: {
|
||||
trigger: 'click',
|
||||
rootClose: true,
|
||||
className: 'm-l-xs',
|
||||
content:
|
||||
'当配置初始化接口后,组件初始就会拉取接口数据,可以通过以下配置修改。',
|
||||
placement: 'left'
|
||||
},
|
||||
body: [
|
||||
{
|
||||
name: 'initFetch',
|
||||
type: 'radios',
|
||||
inline: true,
|
||||
onChange: () => {},
|
||||
// pipeIn: (value:any) => typeof value === 'boolean' ? value : '1'
|
||||
options: [
|
||||
setSchemaTpl(
|
||||
'initFetch',
|
||||
(overrides: {visibleOn?: string; name?: string} = {}) => {
|
||||
const visibleOn = get(overrides, 'visibleOn', 'this.initApi');
|
||||
const fieldName = get(overrides, 'name', 'initFetch');
|
||||
const label = get(overrides, 'label', '是否初始加载');
|
||||
|
||||
return {
|
||||
type: 'group',
|
||||
label: tipedLabel(
|
||||
label,
|
||||
'当配置初始化接口后,组件初始就会拉取接口数据,可以通过以下配置修改。'
|
||||
),
|
||||
visibleOn,
|
||||
direction: 'vertical',
|
||||
body: [
|
||||
{
|
||||
label: '是',
|
||||
value: true
|
||||
name: fieldName,
|
||||
type: 'radios',
|
||||
inline: true,
|
||||
onChange: () => {},
|
||||
// pipeIn: (value:any) => typeof value === 'boolean' ? value : '1'
|
||||
options: [
|
||||
{
|
||||
label: '是',
|
||||
value: true
|
||||
},
|
||||
|
||||
{
|
||||
label: '否',
|
||||
value: false
|
||||
},
|
||||
|
||||
{
|
||||
label: '表达式',
|
||||
value: ''
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
label: '否',
|
||||
value: false
|
||||
},
|
||||
|
||||
{
|
||||
label: '表达式',
|
||||
value: ''
|
||||
}
|
||||
getSchemaTpl('valueFormula', {
|
||||
label: '',
|
||||
name: `${fieldName}On`,
|
||||
autoComplete: false,
|
||||
visibleOn: `typeof this.${fieldName} !== "boolean"`,
|
||||
placeholder: '如:this.id 表示有 id 值时初始加载',
|
||||
className: 'm-t-n-sm'
|
||||
})
|
||||
// {
|
||||
// name: `${fieldName}On`,
|
||||
// autoComplete: false,
|
||||
// visibleOn: `typeof this.${fieldName} !== "boolean"`,
|
||||
// type: 'input-text',
|
||||
// placeholder: '如:this.id 表示有 id 值时初始加载',
|
||||
// className: 'm-t-n-sm'
|
||||
// }
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
name: 'initFetchOn',
|
||||
autoComplete: false,
|
||||
visibleOn: 'typeof this.initFetch !== "boolean"',
|
||||
type: 'input-text',
|
||||
placeholder: '如:this.id 表示有 id 值时初始加载',
|
||||
className: 'm-t-n-sm'
|
||||
}
|
||||
]
|
||||
});
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
setSchemaTpl('proxy', {
|
||||
type: 'switch',
|
||||
@ -409,31 +427,35 @@ setSchemaTpl('proxy', {
|
||||
});
|
||||
|
||||
setSchemaTpl('apiControl', (patch: any = {}) => {
|
||||
const {name, label, value, description, sampleBuilder, ...rest} = patch;
|
||||
const {name, label, value, description, sampleBuilder, apiDesc, ...rest} =
|
||||
patch;
|
||||
|
||||
return {
|
||||
type: 'ae-apiControl',
|
||||
label,
|
||||
name,
|
||||
description,
|
||||
mode: 'normal',
|
||||
labelRemark: sampleBuilder
|
||||
? {
|
||||
icon: '',
|
||||
label: '示例',
|
||||
label: false,
|
||||
title: '接口返回示例',
|
||||
icon: 'fas fa-code',
|
||||
className: 'm-l-xs ae-ApiSample-icon',
|
||||
tooltipClassName: 'ae-ApiSample-tooltip',
|
||||
render: (data: any) => (
|
||||
<Html
|
||||
className="ae-ApiSample"
|
||||
inline={false}
|
||||
html={`
|
||||
<pre><code>${sampleBuilder(data)}</code></pre>
|
||||
`}
|
||||
/>
|
||||
),
|
||||
children: () => {
|
||||
return (
|
||||
<Html
|
||||
className="ae-ApiSample"
|
||||
inline={false}
|
||||
html={`<pre><code>${sampleBuilder()}</code></pre>${
|
||||
apiDesc
|
||||
? `<span class="ae-ApiSample-desc">${apiDesc}</span>`
|
||||
: ''
|
||||
}`}
|
||||
/>
|
||||
);
|
||||
},
|
||||
trigger: 'click',
|
||||
className: 'm-l-xs',
|
||||
rootClose: true,
|
||||
placement: 'left'
|
||||
}
|
||||
@ -442,6 +464,50 @@ setSchemaTpl('apiControl', (patch: any = {}) => {
|
||||
};
|
||||
});
|
||||
|
||||
setSchemaTpl('interval', (more: any = {}) => ({
|
||||
type: 'ae-switch-more',
|
||||
label: '定时刷新',
|
||||
name: 'interval',
|
||||
formType: 'extend',
|
||||
bulk: true,
|
||||
mode: 'normal',
|
||||
form: {
|
||||
body: [
|
||||
getSchemaTpl('withUnit', {
|
||||
label: '刷新间隔',
|
||||
name: 'interval',
|
||||
control: {
|
||||
type: 'input-number',
|
||||
name: 'interval',
|
||||
value: 1000
|
||||
},
|
||||
unit: '毫秒'
|
||||
})
|
||||
]
|
||||
},
|
||||
...more
|
||||
}));
|
||||
|
||||
setSchemaTpl('silentPolling', () =>
|
||||
getSchemaTpl('switch', {
|
||||
label: tipedLabel('静默刷新', '设置自动定时刷新时是否显示loading'),
|
||||
name: 'silentPolling',
|
||||
visibleOn: '!!this.interval'
|
||||
})
|
||||
);
|
||||
|
||||
setSchemaTpl('stopAutoRefreshWhen', (extra: any = {}) =>
|
||||
getSchemaTpl('valueFormula', {
|
||||
name: 'stopAutoRefreshWhen',
|
||||
label: tipedLabel(
|
||||
'定时刷新停止',
|
||||
'定时刷新一旦设置会一直刷新,除非给出表达式,条件满足后则停止刷新'
|
||||
),
|
||||
visibleOn: '!!this.interval',
|
||||
...extra
|
||||
})
|
||||
);
|
||||
|
||||
/**
|
||||
* 接口控件
|
||||
*/
|
||||
|
@ -2,9 +2,11 @@ import {
|
||||
setSchemaTpl,
|
||||
getSchemaTpl,
|
||||
defaultValue,
|
||||
isObject
|
||||
isObject,
|
||||
tipedLabel,
|
||||
DSField
|
||||
} from 'amis-editor-core';
|
||||
import {remarkTpl, tipedLabel} from '../component/BaseControl';
|
||||
import {remarkTpl} from '../component/BaseControl';
|
||||
import {SchemaObject} from 'amis/lib/Schema';
|
||||
import flatten from 'lodash/flatten';
|
||||
import {InputComponentName} from '../component/InputComponentName';
|
||||
@ -22,13 +24,46 @@ setSchemaTpl('switch', {
|
||||
inputClassName: 'is-inline '
|
||||
});
|
||||
|
||||
/**
|
||||
* 分割线
|
||||
*/
|
||||
setSchemaTpl('divider', {
|
||||
type: 'divider',
|
||||
className: 'mx-0'
|
||||
});
|
||||
|
||||
/**
|
||||
* 带单位的控件
|
||||
*/
|
||||
setSchemaTpl(
|
||||
'withUnit',
|
||||
(config: {name: string; label: string; control: any; unit: string}) => {
|
||||
return {
|
||||
type: 'input-group',
|
||||
name: config.name,
|
||||
label: config.label,
|
||||
body: [
|
||||
config.control,
|
||||
{
|
||||
type: 'tpl',
|
||||
addOnclassName: 'border-0 bg-none',
|
||||
tpl: config.unit
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* 表单项字段name
|
||||
*/
|
||||
setSchemaTpl('formItemName', {
|
||||
label: '字段名',
|
||||
name: 'name',
|
||||
type: 'ae-DataBindingControl'
|
||||
type: 'ae-DataBindingControl',
|
||||
onBindingChange(field: DSField, onBulkChange: (value: any) => void) {
|
||||
onBulkChange(field.resolveEditSchema?.() || {label: field.label});
|
||||
}
|
||||
// validations: {
|
||||
// matchRegexp: /^[a-z\$][a-z0-0\-_]*$/i
|
||||
// },
|
||||
@ -38,37 +73,45 @@ setSchemaTpl('formItemName', {
|
||||
// validateOnChange: false
|
||||
});
|
||||
|
||||
setSchemaTpl('formItemMode', {
|
||||
label: '布局',
|
||||
name: 'mode',
|
||||
type: 'button-group-select',
|
||||
option: '继承',
|
||||
horizontal: {
|
||||
left: 2,
|
||||
justify: true
|
||||
},
|
||||
// className: 'w-full',
|
||||
pipeIn: defaultValue(''),
|
||||
options: [
|
||||
{
|
||||
label: '内联',
|
||||
value: 'inline'
|
||||
setSchemaTpl(
|
||||
'formItemMode',
|
||||
(config: {
|
||||
// 是不是独立表单,没有可以集成的内容
|
||||
isForm: boolean;
|
||||
}) => ({
|
||||
label: '布局',
|
||||
name: 'mode',
|
||||
type: 'button-group-select',
|
||||
option: '继承',
|
||||
horizontal: {
|
||||
left: 2,
|
||||
justify: true
|
||||
},
|
||||
{
|
||||
label: '水平',
|
||||
value: 'horizontal'
|
||||
},
|
||||
{
|
||||
label: '垂直',
|
||||
value: 'normal'
|
||||
},
|
||||
{
|
||||
label: '继承',
|
||||
value: ''
|
||||
}
|
||||
],
|
||||
pipeOut: (v: string) => (v ? v : undefined)
|
||||
});
|
||||
// className: 'w-full',
|
||||
pipeIn: defaultValue(''),
|
||||
options: [
|
||||
{
|
||||
label: '内联',
|
||||
value: 'inline'
|
||||
},
|
||||
{
|
||||
label: '水平',
|
||||
value: 'horizontal'
|
||||
},
|
||||
{
|
||||
label: '垂直',
|
||||
value: 'normal'
|
||||
},
|
||||
config?.isForm
|
||||
? null
|
||||
: {
|
||||
label: '继承',
|
||||
value: ''
|
||||
}
|
||||
].filter(i => i),
|
||||
pipeOut: (v: string) => (v ? v : undefined)
|
||||
})
|
||||
);
|
||||
|
||||
setSchemaTpl('formItemInline', {
|
||||
type: 'switch',
|
||||
@ -243,37 +286,31 @@ setSchemaTpl(
|
||||
key: string;
|
||||
visibleOn: string;
|
||||
body: Array<any>;
|
||||
}>,
|
||||
rendererSchema?: any
|
||||
}>
|
||||
) => {
|
||||
let currentKey = rendererSchema
|
||||
? `${rendererSchema.$$id}_${rendererSchema.type}_${rendererSchema.configTitle}_collapse`
|
||||
: `config_collapse`;
|
||||
currentKey = currentKey.replace(/-/g, '__');
|
||||
|
||||
const collapseGroupBody = config
|
||||
.filter(
|
||||
item => item && Array.isArray(item?.body) && item?.body.length > 0
|
||||
)
|
||||
.map((item, index) => ({
|
||||
.map(item => ({
|
||||
type: 'collapse',
|
||||
collapsed: false,
|
||||
headingClassName: 'ae-formItemControl-header',
|
||||
bodyClassName: 'ae-formItemControl-body',
|
||||
...item,
|
||||
key: `${currentKey}_${item.key || index.toString()}`,
|
||||
key: item.title,
|
||||
body: flatten(item.body)
|
||||
}));
|
||||
|
||||
return {
|
||||
type: 'collapse-group',
|
||||
key: currentKey,
|
||||
activeKey: collapseGroupBody.map(panel => panel.title),
|
||||
expandIconPosition: 'right',
|
||||
expandIcon: {
|
||||
type: 'icon',
|
||||
icon: 'chevron-right'
|
||||
},
|
||||
className: 'ae-formItemControl ae-styleControl',
|
||||
activeKey: collapseGroupBody.map((group, index) => group.key),
|
||||
body: collapseGroupBody
|
||||
};
|
||||
}
|
||||
@ -346,7 +383,7 @@ setSchemaTpl(
|
||||
body: [
|
||||
{
|
||||
type: 'ae-formulaControl',
|
||||
label: config?.label || '默认值',
|
||||
label: config?.label ?? '默认值',
|
||||
name: config?.name || 'value',
|
||||
rendererSchema: curRendererSchema,
|
||||
rendererWrapper: config?.rendererWrapper,
|
||||
@ -509,28 +546,29 @@ setSchemaTpl('size', {
|
||||
});
|
||||
|
||||
setSchemaTpl('name', {
|
||||
label: '名字',
|
||||
label: tipedLabel(
|
||||
'名字',
|
||||
'需要联动时才需要,其他组件可以通过这个名字跟当前组件联动'
|
||||
),
|
||||
name: 'name',
|
||||
type: 'input-text',
|
||||
description: '需要联动时才需要,其他组件可以通过这个名字跟当前组件联动',
|
||||
placeholder: '请输入字母或者数字'
|
||||
});
|
||||
|
||||
setSchemaTpl('reload', {
|
||||
label: '刷新目标组件',
|
||||
name: 'reload',
|
||||
asFormItem: true,
|
||||
// type: 'input-text',
|
||||
component: InputComponentName,
|
||||
description:
|
||||
'可以指定操作完成后刷新目标组件,请填写目标组件的 <code>name</code> 属性,多个组件请用<code>,</code>隔开,如果目标组件为表单项,请先填写表单的名字,再用<code>.</code>连接表单项的名字如:<code>xxForm.xxControl</code>。另外如果刷新目标对象设置为 <code>window</code>,则会刷新整个页面。',
|
||||
labelRemark: {
|
||||
trigger: 'click',
|
||||
className: 'm-l-xs',
|
||||
rootClose: true,
|
||||
content:
|
||||
'设置名字后,当前组件操作完成会触发目标组件(根据设置的名字)的刷新。',
|
||||
placement: 'left'
|
||||
label: tipedLabel(
|
||||
'刷新目标组件',
|
||||
'可以指定操作完成后刷新目标组件,请填写目标组件的 <code>name</code> 属性,多个组件请用<code>,</code>隔开,如果目标组件为表单项,请先填写表单的名字,再用<code>.</code>连接表单项的名字如:<code>xxForm.xxControl</code>。另外如果刷新目标对象设置为 <code>window</code>,则会刷新整个页面。'
|
||||
),
|
||||
placeholder: '请输入组件name',
|
||||
mode: 'horizontal',
|
||||
horizontal: {
|
||||
left: 4,
|
||||
justify: true
|
||||
}
|
||||
});
|
||||
|
||||
@ -577,7 +615,7 @@ setSchemaTpl(
|
||||
? getSchemaTpl('disabled')
|
||||
: null,
|
||||
config?.isFormItem ? getSchemaTpl('clearValueOnHidden') : null
|
||||
]
|
||||
].filter(Boolean)
|
||||
};
|
||||
}
|
||||
);
|
||||
|
@ -1,5 +1,6 @@
|
||||
import {setSchemaTpl, getSchemaTpl, defaultValue} from 'amis-editor-core';
|
||||
import {tipedLabel} from '../component/BaseControl';
|
||||
import {isObject} from 'lodash';
|
||||
import {tipedLabel} from 'amis-editor-core';
|
||||
|
||||
setSchemaTpl('horizontal-align', {
|
||||
type: 'button-group-select',
|
||||
@ -57,47 +58,51 @@ setSchemaTpl('leftRate', {
|
||||
}
|
||||
});
|
||||
|
||||
setSchemaTpl('horizontal', () => {
|
||||
return [
|
||||
{
|
||||
type: 'button-group-select',
|
||||
label: '标题宽度',
|
||||
name: 'horizontal',
|
||||
options: [
|
||||
{label: '继承', value: 'formHorizontal'},
|
||||
{label: '固宽', value: 'leftFixed'},
|
||||
{label: '比例', value: 'leftRate'}
|
||||
],
|
||||
pipeIn(v: any) {
|
||||
if (!v) {
|
||||
return 'formHorizontal';
|
||||
}
|
||||
if (v.leftFixed) {
|
||||
return 'leftFixed';
|
||||
}
|
||||
return 'leftRate';
|
||||
},
|
||||
pipeOut(v: any) {
|
||||
const defaultData = {
|
||||
formHorizontal: undefined,
|
||||
leftFixed: {leftFixed: 'normal'},
|
||||
leftRate: {left: 3, right: 9}
|
||||
};
|
||||
setSchemaTpl(
|
||||
'horizontal',
|
||||
(config: {visibleOn: string; [propName: string]: any}) => {
|
||||
return [
|
||||
{
|
||||
type: 'button-group-select',
|
||||
label: '标题宽度',
|
||||
name: 'horizontal',
|
||||
options: [
|
||||
{label: '继承', value: 'formHorizontal'},
|
||||
{label: '固宽', value: 'leftFixed'},
|
||||
{label: '比例', value: 'leftRate'}
|
||||
],
|
||||
pipeIn(v: any) {
|
||||
if (!v) {
|
||||
return 'formHorizontal';
|
||||
}
|
||||
if (v.leftFixed) {
|
||||
return 'leftFixed';
|
||||
}
|
||||
return 'leftRate';
|
||||
},
|
||||
pipeOut(v: any) {
|
||||
const defaultData = {
|
||||
formHorizontal: undefined,
|
||||
leftFixed: {leftFixed: 'normal'},
|
||||
leftRate: {left: 3, right: 9}
|
||||
};
|
||||
|
||||
// @ts-ignore
|
||||
return defaultData[v];
|
||||
// @ts-ignore
|
||||
return defaultData[v];
|
||||
},
|
||||
visibleOn: 'this.mode == "horizontal" && this.label !== false',
|
||||
...(isObject(config) ? config : {})
|
||||
},
|
||||
visibleOn: 'this.mode == "horizontal" && this.label !== false'
|
||||
},
|
||||
{
|
||||
type: 'container',
|
||||
className: 'ae-ExtendMore mb-3',
|
||||
visibleOn:
|
||||
'this.mode == "horizontal" && this.horizontal && this.label !== false',
|
||||
body: [getSchemaTpl('leftFixed'), getSchemaTpl('leftRate')]
|
||||
}
|
||||
];
|
||||
});
|
||||
{
|
||||
type: 'container',
|
||||
className: 'ae-ExtendMore mb-3',
|
||||
visibleOn:
|
||||
'this.mode == "horizontal" && this.horizontal && this.label !== false',
|
||||
body: [getSchemaTpl('leftFixed'), getSchemaTpl('leftRate')]
|
||||
}
|
||||
];
|
||||
}
|
||||
);
|
||||
|
||||
setSchemaTpl('subFormItemMode', {
|
||||
label: '子表单展示模式',
|
||||
|
@ -1,5 +1,5 @@
|
||||
import {setSchemaTpl, getSchemaTpl, defaultValue} from 'amis-editor-core';
|
||||
import {tipedLabel} from '../component/BaseControl';
|
||||
import {tipedLabel} from 'amis-editor-core';
|
||||
import {SchemaObject} from 'amis/lib/Schema';
|
||||
|
||||
setSchemaTpl('options', {
|
||||
@ -114,7 +114,7 @@ setSchemaTpl('tree', {
|
||||
|
||||
setSchemaTpl('multiple', (schema: any = {}) => {
|
||||
return {
|
||||
type: 'ae-Switch-More',
|
||||
type: 'ae-switch-more',
|
||||
mode: 'normal',
|
||||
name: 'multiple',
|
||||
label: '可多选',
|
||||
|
@ -9,6 +9,6 @@
|
||||
"../../node_modules/@types"
|
||||
]
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"include": ["src/**/*", "../amis-editor-core/src/builder"],
|
||||
"references": []
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user