Merge branch 'feat-optimize-5' of ssh://icode.baidu.com:8235/baidu/amis/editor into feat-optimize-5

Change-Id: I4069efb456327526eb44cca5de88a5908602e636
This commit is contained in:
jiatianqi 2022-08-11 19:33:08 +08:00
commit 4a6bfebbe6
8 changed files with 1083 additions and 565 deletions

View File

@ -155,6 +155,7 @@ import './renderer/DataMappingControl';
import './renderer/DataPickerControl';
import './renderer/event-control/index';
import './renderer/TreeOptionControl';
import './renderer/TransferTableControl';
export * from './component/BaseControl';
export * from './icons/index';

View File

@ -84,6 +84,9 @@ export class AnchorNavPlugin extends BasePlugin {
draggable: true,
minLength: 1,
addButtonText: '添加锚点',
deleteBtn: {
icon: 'fa fa-trash'
},
items: [
{
type: 'input-text',
@ -150,7 +153,8 @@ export class AnchorNavPlugin extends BasePlugin {
value: '1'
}
]
}
},
getSchemaTpl('status')
])
},
{

View File

@ -1,14 +1,16 @@
import React from 'react';
import {registerEditorPlugin} from 'amis-editor-core';
import {
registerEditorPlugin,
BaseEventContext,
BasePlugin,
RegionConfig,
RendererInfo
RendererInfo,
getSchemaTpl,
noop
} from 'amis-editor-core';
import {defaultValue, getSchemaTpl} from 'amis-editor-core';
import {noop} from 'amis-editor-core';
import {cloneDeep, assign} from 'lodash';
import {getEventControlConfig} from '../renderer/event-control/helper';
import {tipedLabel} from '../component/BaseControl';
export class DialogPlugin extends BasePlugin {
// 关联渲染器名字
@ -83,108 +85,152 @@ export class DialogPlugin extends BasePlugin {
];
panelTitle = '弹框';
panelJustify = true;
panelBodyCreator = (context: BaseEventContext) => {
return getSchemaTpl('tabs', [
{
title: '常规',
body: [
title: '属性',
body: getSchemaTpl('collapseGroup', [
{
label: '标题',
type: 'input-text',
name: 'title'
},
getSchemaTpl('switch', {
label: '数据映射',
name: 'data',
className: 'block m-b-xs',
pipeIn: (value: any) => !!value,
pipeOut: (value: any) => (value ? {'&': '$$'} : null)
}),
{
type: 'tpl',
visibleOn: '!this.data',
tpl:
'<p class="text-sm text-muted">当没开启数据映射时,弹框中默认会拥有触发打开弹框按钮所在环境的所有数据。</p>'
},
{
type: 'input-kv',
syncDefaultValue: false,
name: 'data',
visibleOn: 'this.data',
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>',
messages: {
validateFailed: '数据映射中存在错误,请仔细检查'
}
},
getSchemaTpl('switch', {
label: '按 Esc 关闭弹框',
name: 'closeOnEsc',
value: false
}),
getSchemaTpl('switch', {
label: '点击弹框外区域关闭弹框',
name: 'closeOnOutside',
value: false
})
]
title: '基本',
body: [
{
label: '标题',
type: 'input-text',
name: 'title'
},
{
label: '尺寸',
type: 'button-group-select',
value: 'md',
name: 'size',
size: 'sm',
options: [
{
label: '小',
value: 'sm'
},
{
label: '中',
value: 'md'
},
{
label: '大',
value: 'lg'
},
{
label: '超大',
value: 'xl'
}
]
},
getSchemaTpl('switch', {
label: '展示关闭按钮',
name: 'showCloseButton',
value: true
}),
getSchemaTpl('switch', {
label: '可按 Esc 关闭',
name: 'closeOnEsc',
value: false
}),
getSchemaTpl('switch', {
label: '左下角展示报错消息',
name: 'showErrorMsg',
value: true
}),
getSchemaTpl('switch', {
label: '左下角展示loading动画',
name: 'showLoading',
value: true
}),
getSchemaTpl('switch', {
label: tipedLabel(
'数据映射',
'<div> 当开启数据映射时,弹框中的数据只会包含设置的部分,请绑定数据。如:{"a": "${a}", "b": 2}。</div>'
+ '<div>当值为 __undefined时表示删除对应的字段可以结合{"&": "$$"}来达到黑名单效果。</div>'
),
name: 'dataMapSwitch',
value: false,
className: 'm-b-xs',
onChange: (value: any, oldValue: any, model: any, form: any) => {
const newDataValue = value ? {} : null;
form.setValues({
__dataMap: newDataValue,
data: newDataValue
});
}
}),
{
type: 'alert',
level: 'info',
visibleOn: 'this.dataMapSwitch',
className: 'relative',
body: [
{
type: 'tpl',
tpl: '${data["&"] ? "已开启定制参数功能,可点击关闭该功能。" : "如果需要在默认数据的基础上定制参数请配置开启参数定制再定义key和value。"}'
},
{
type: 'button',
label: '${data["&"] ? "立即关闭" : "立即开启"}',
level: 'link',
className: 'absolute bottom-3 right-10',
onClick: (e: any, props: any) => {
const newData = props.data.data?.['&'] === '$$' ? {} : {'&': '$$'};
// 用onBulkChange保证代码视图和编辑区域数据保持同步
props.onBulkChange({
data: newData,
__dataMap: {}
});
}
}
],
showCloseButton: true
},
getSchemaTpl('combo-container', {
type: 'input-kv',
syncDefaultValue: false,
name: '__dataMap',
value: null,
visibleOn: 'this.dataMapSwitch',
className: 'block -mt-5',
deleteBtn: {
icon: 'fa fa-trash'
},
onChange: (value: any, oldValue: any, model: any, form: any) => {
// 用assign保证'&'第一个被遍历到
const newDataMap = form.data.data?.['&'] ?
assign({'&': '$$'}, value) : cloneDeep(value);
form.setValues({
data: newDataMap
});
form.setValues({
data: newDataMap
});
}
}),
]
}
])
},
{
title: '外观',
body: [
body: getSchemaTpl('collapseGroup', [
{
label: '尺寸',
type: 'button-group-select',
name: 'size',
size: 'sm',
className: 'block',
pipeIn: defaultValue(''),
options: [
{
label: '小',
value: 'sm'
},
{
label: '默认',
value: ''
},
{
label: '中',
value: 'md'
},
{
label: '大',
value: 'lg'
},
{
label: '超大',
value: 'xl'
}
title: 'CSS类名',
body: [
getSchemaTpl('className', {
name: 'className',
label: '外层'
}),
getSchemaTpl('className', {
name: 'bodyClassName',
label: '内容区域'
})
]
},
getSchemaTpl('switch', {
label: '是否显示关闭按钮',
name: 'showCloseButton',
value: true
}),
getSchemaTpl('className', {
name: 'headerClassName',
label: '顶部 CSS 类名'
}),
getSchemaTpl('className', {
name: 'bodyClassName',
label: '内容 CSS 类名'
})
]
}
])
},
{
title: '事件',

View File

@ -1,14 +1,17 @@
import {registerEditorPlugin} from 'amis-editor-core';
import {
registerEditorPlugin,
BaseEventContext,
BasePlugin,
RegionConfig,
RendererInfo
RendererInfo,
defaultValue,
getSchemaTpl,
noop
} from 'amis-editor-core';
import {defaultValue, getSchemaTpl} from 'amis-editor-core';
import {noop} from 'amis-editor-core';
import {assign, cloneDeep} from 'lodash';
import {getEventControlConfig} from '../renderer/event-control/helper';
import {InlineModal} from './Dialog';
import {tipedLabel} from '../component/BaseControl';
export class DrawerPlugin extends BasePlugin {
// 关联渲染器名字
@ -83,153 +86,213 @@ export class DrawerPlugin extends BasePlugin {
];
panelTitle = '弹框';
panelJustify = true;
panelBodyCreator = (context: BaseEventContext) => {
return getSchemaTpl('tabs', [
{
title: '常规',
body: [
title: '属性',
body: getSchemaTpl('collapseGroup', [
{
label: '标题',
type: 'input-text',
name: 'title'
},
// {
// children: (
// <Button
// size="sm"
// className="m-b-sm"
// level="info"
// block
// onClick={() => this.manager.showInsertPanel('body')}
// >
// 新增内容
// </Button>
// )
// },
{
type: 'divider'
},
{
label: '位置',
type: 'button-group-select',
name: 'position',
value: 'right',
size: 'sm',
mode: 'inline',
className: 'block',
options: [
title: '基本',
body: [
{
label: '左',
value: 'left'
label: '标题',
type: 'input-text',
name: 'title'
},
{
label: '上',
value: 'top'
type: 'button-group-select',
name: 'position',
label: '位置',
value: 'right',
mode: 'horizontal',
options: [
{
label: '左',
value: 'left'
},
{
label: '上',
value: 'top'
},
{
label: '右',
value: 'right'
},
{
label: '下',
value: 'bottom'
}
]
},
{
label: '右',
value: 'right'
type: 'button-group-select',
name: 'size',
label: '尺寸',
value: 'md',
size: 'sm',
mode: 'horizontal',
options: [
{
label: '超小',
value: 'xs'
},
{
label: '小',
value: 'sm'
},
{
label: '中',
value: 'md'
},
{
label: '大',
value: 'lg'
},
{
label: '超大',
value: 'xl'
}
]
},
getSchemaTpl('switch', {
name: 'overlay',
label: '显示蒙层',
pipeIn: defaultValue(true)
}),
getSchemaTpl('switch', {
name: 'showCloseButton',
label: '展示关闭按钮',
pipeIn: defaultValue(true)
}),
getSchemaTpl('switch', {
name: 'closeOnOutside',
label: '点击外部关闭'
}),
getSchemaTpl('switch', {
label: '可按 Esc 关闭',
name: 'closeOnEsc'
}),
getSchemaTpl('switch', {
name: 'resizable',
label: '可拖拽抽屉大小',
value: false
}),
getSchemaTpl('switch', {
label: tipedLabel(
'数据映射',
'<div> 当开启数据映射时,弹框中的数据只会包含设置的部分,请绑定数据。如:{"a": "${a}", "b": 2}。</div>'
+ '<div>当值为 __undefined时表示删除对应的字段可以结合{"&": "$$"}来达到黑名单效果。</div>'
),
name: 'dataMapSwitch',
value: false,
className: 'm-b-xs',
onChange: (value: any, oldValue: any, model: any, form: any) => {
const newDataValue = value ? {} : null;
form.setValues({
__dataMap: newDataValue,
data: newDataValue
});
}
}),
{
label: '下',
value: 'bottom'
}
],
description: '定义弹框从什么位置呼出'
},
getSchemaTpl('switch', {
label: '数据映射',
name: 'data',
className: 'm-b-xs',
pipeIn: (value: any) => !!value,
pipeOut: (value: any) => (value ? {'&': '$$'} : null)
}),
{
type: 'tpl',
visibleOn: '!this.data',
tpl:
'<p class="text-sm text-muted">当没开启数据映射时,弹框中默认会拥有触发打开弹框按钮所在环境的所有数据。</p>'
},
{
type: 'input-kv',
syncDefaultValue: false,
name: 'data',
visibleOn: 'this.data',
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>'
},
getSchemaTpl('switch', {
name: 'closeOnOutside',
label: '点击外部关闭弹框'
}),
getSchemaTpl('switch', {
label: '按 Esc 可关闭',
name: 'closeOnEsc'
})
]
type: 'alert',
level: 'info',
visibleOn: 'this.dataMapSwitch',
className: 'relative',
body: [
{
type: 'tpl',
tpl: '${data["&"] ? "已开启定制参数功能,可点击关闭该功能。" : "如果需要在默认数据的基础上定制参数请配置开启参数定制再定义key和value。"}'
},
{
type: 'button',
label: '${data["&"] ? "立即关闭" : "立即开启"}',
level: 'link',
className: 'absolute bottom-3 right-10',
onClick: (e: any, props: any) => {
const newData = props.data.data?.['&'] === '$$' ? {} : {'&': '$$'};
// 用onBulkChange保证代码视图和编辑区域数据保持同步
props.onBulkChange({
data: newData,
__dataMap: {}
});
}
}
],
showCloseButton: true
},
getSchemaTpl('combo-container', {
type: 'input-kv',
syncDefaultValue: false,
name: '__dataMap',
value: null,
visibleOn: 'this.dataMapSwitch',
className: 'block -mt-5',
deleteBtn: {
icon: 'fa fa-trash'
},
onChange: (value: any, oldValue: any, model: any, form: any) => {
// 用assign保证'&'第一个被遍历到
const newDataMap = form.data.data?.['&'] ?
assign({'&': '$$'}, value) : cloneDeep(value);
form.setValues({
data: newDataMap
});
}
})
]
}
])
},
{
title: '外观',
body: [
body: getSchemaTpl('collapseGroup', [
{
label: '尺寸',
type: 'button-group-select',
name: 'size',
size: 'sm',
mode: 'inline',
className: 'block',
options: [
title: '基本',
body: [
{
label: '超小',
value: 'xs'
type: 'input-text',
name: 'width',
label: tipedLabel(
'宽度',
'位置为 "左" 或 "右" 时生效。 默认宽度为"尺寸"字段配置的宽度,值单位默认为 px也支持百分比等单位 100%'
),
disabledOn: 'this.position === "top" || this.position === "bottom"',
tooltip: '位置为 为 "左" 或 "右" 时生效'
},
{
label: '小',
value: 'sm'
},
{
label: '中',
value: 'md'
},
{
label: '大',
value: 'lg'
},
{
label: '超大',
value: 'xl'
type: 'input-text',
name: 'height',
label: tipedLabel(
'高度',
'位置为 "上" 或 "下" 时生效。 默认宽度为"尺寸"字段配置的高度,值单位默认为 px也支持百分比等单位 100%'
),
disabledOn: 'this.position === "left" || this.position === "right"'
}
]
},
getSchemaTpl('switch', {
name: 'overlay',
label: '是否显示蒙层',
pipeIn: defaultValue(true)
}),
getSchemaTpl('switch', {
name: 'resizable',
label: '可拉拽',
description: '定义弹框是否可拉拽调整大小',
pipeIn: defaultValue(false)
}),
getSchemaTpl('className'),
getSchemaTpl('className', {
label: 'bodyClassName 类名',
name: 'bodyClassName'
})
]
{
title: 'CSS类名',
body: [
getSchemaTpl('className', {
label: '外层'
}),
getSchemaTpl('className', {
label: '标题区域',
name: 'headClassName'
}),
getSchemaTpl('className', {
label: '内容区域',
name: 'bodyClassName'
}),
getSchemaTpl('className', {
label: '页脚区域',
name: 'footClassName'
})
]
}
])
},
{
title: '事件',

View File

@ -59,58 +59,90 @@ export class ButtonToolbarControlPlugin extends BasePlugin {
panelTitle = '工具栏';
panelJustify = true;
panelBodyCreator = (context: BaseEventContext) => {
return formItemControl(
return getSchemaTpl('tabs', [
{
common: {
replace: true,
body: [
getSchemaTpl('formItemName', {
required: true
}),
getSchemaTpl('label'),
getSchemaTpl('remark'),
getSchemaTpl('labelRemark'),
getSchemaTpl('description')
]
},
option: {
title: '按钮管理',
replace: true,
body: [
title: '属性',
body: [
getSchemaTpl('collapseGroup', [
{
name: 'buttons',
type: 'combo',
label: '',
multiple: true,
addable: true,
minLength: 1,
draggable: true,
draggableTip: '',
editable: false,
visibleOn: 'this.buttons && this.buttons.length',
items: [
{
type: 'tpl',
inline: false,
tpl:
'<span class="label label-default"><% if (data.type === "button-group") { %> 按钮组 <% } else { %><%= data.label %><% if (data.icon) { %><i class="<%= data.icon %>"/><% }%><% } %></span>'
}
],
addButtonText: '新增按钮',
scaffold: {
type: 'button',
label: '按钮'
}
}
]
},
event: {
hidden: false
}
title: '基本',
body: [
getSchemaTpl('formItemName', {
required: true
}),
getSchemaTpl('label'),
getSchemaTpl('valueFormula', {
rendererSchema: {
type: 'input-text'
}
}),
getSchemaTpl('labelRemark'),
getSchemaTpl('remark'),
getSchemaTpl('description'),
getSchemaTpl('combo-container', {
type: 'combo',
label: '按钮管理',
name: 'buttons',
mode: 'normal',
multiple: true,
addable: true,
minLength: 1,
draggable: true,
editable: false,
items: [
{
type: 'tpl',
inline: false,
className: 'p-t-xs',
tpl: '<span class="label label-default"><% if (data.type === "button-group") { %> 按钮组 <% } else { %><%= data.label %><% if (data.icon) { %><i class="<%= data.icon %>"/><% }%><% } %></span>'
}
],
addButtonText: '新增按钮',
scaffold: {
type: 'button',
label: '按钮'
}
}),
]
},
getSchemaTpl('status', {
isFormItem: true,
})
]),
]
},
context
);
{
title: '外观',
body: [
getSchemaTpl('collapseGroup', [
{
title: '基本',
body: [
getSchemaTpl('formItemMode'),
getSchemaTpl('horizontal', {
label: '',
visibleOn:
'data.mode == "horizontal" && data.label !== false && data.horizontal'
}),
]
},
getSchemaTpl('style:classNames', {
isFormItem: true,
schema: [
getSchemaTpl('className', {
label: '描述',
name: 'descriptionClassName',
visibleOn: "this.description"
})
]
}),
])
]
}
]);
};
}

View File

@ -218,6 +218,10 @@ export class TabsTransferPlugin extends BasePlugin {
}
];
notRenderFormZone = true;
panelJustify = true;
panelDefinitions = {
options: {
label: '选项 Options',
@ -269,65 +273,64 @@ export class TabsTransferPlugin extends BasePlugin {
{
title: '属性',
body: getSchemaTpl('collapseGroup', [
getSchemaTpl('switchDefaultValue'),
{
type: 'select',
name: 'value',
label: '默认值',
source: '${options}',
multiple: true,
visibleOn: 'typeof this.value !== "undefined"'
},
title: '基本',
body: [
getSchemaTpl('formItemName', {
required: true
}),
getSchemaTpl('label'),
getSchemaTpl('searchable'),
getSchemaTpl('api', {
label: '检索接口',
name: 'searchApi'
}),
{
label: '查询时勾选展示模式',
name: 'searchResultMode',
type: 'select',
mode: 'inline',
className: 'w-full',
options: [
getSchemaTpl('searchable'),
getSchemaTpl('api', {
label: '检索接口',
name: 'searchApi'
}),
{
label: '列表形式',
value: 'list'
label: '查询时勾选展示模式',
name: 'searchResultMode',
type: 'select',
mode: 'normal',
options: [
{
label: '列表形式',
value: 'list'
},
{
label: '表格形式',
value: 'table'
},
{
label: '树形选择形式',
value: 'tree'
},
{
label: '级联选择形式',
value: 'chained'
}
]
},
{
label: '表格形式',
value: 'table'
},
{
label: '树形选择形式',
value: 'tree'
},
{
label: '级联选择形式',
value: 'chained'
}
getSchemaTpl('sortable'),
getSchemaTpl('formulaControl', {
label: '左侧选项标题',
name: 'selectTitle',
type: 'input-text',
inputClassName: 'is-inline '
}),
getSchemaTpl('formulaControl', {
label: '右侧结果标题',
name: 'resultTitle',
type: 'input-text',
inputClassName: 'is-inline '
})
]
},
getSchemaTpl('sortable'),
{
label: '左侧的标题文字',
name: 'selectTitle',
type: 'input-text'
},
{
label: '右侧结果的标题文字',
name: 'resultTitle',
type: 'input-text'
},
getSchemaTpl('fieldSet', {
title: '选项',
body: [
{
@ -340,7 +343,8 @@ export class TabsTransferPlugin extends BasePlugin {
getSchemaTpl('extractValue'),
getSchemaTpl('autoFill')
]
})
},
getSchemaTpl('status', {isFormItem: true})
])
},
{

View File

@ -7,6 +7,9 @@ import {
RendererPluginEvent
} from 'amis-editor-core';
import {ValidatorTag} from '../../validator';
import {tipedLabel} from '../../component/BaseControl';
export class TransferPlugin extends BasePlugin {
// 关联渲染器名字
rendererName = 'transfer';
@ -26,43 +29,28 @@ export class TransferPlugin extends BasePlugin {
name: 'transfer',
options: [
{
label: '法师',
children: [
{
label: '诸葛亮',
value: 'zhugeliang'
}
]
label: '诸葛亮',
value: 'zhugeliang'
},
{
label: '战士',
children: [
{
label: '曹操',
value: 'caocao'
},
{
label: '钟无艳',
value: 'zhongwuyan'
}
]
label: '曹操',
value: 'caocao'
},
{
label: '打野',
children: [
{
label: '李白',
value: 'libai'
},
{
label: '韩信',
value: 'hanxin'
},
{
label: '云中君',
value: 'yunzhongjun'
}
]
label: '钟无艳',
value: 'zhongwuyan'
},
{
label: '李白',
value: 'libai'
},
{
label: '韩信',
value: 'hanxin'
},
{
label: '云中君',
value: 'yunzhongjun'
}
]
};
@ -181,7 +169,9 @@ export class TransferPlugin extends BasePlugin {
}
};
// notRenderFormZone = true;
notRenderFormZone = true;
panelJustify = true;
panelBodyCreator = (context: BaseEventContext) => {
const renderer: any = context.info.renderer;
@ -190,231 +180,150 @@ export class TransferPlugin extends BasePlugin {
{
title: '属性',
body: getSchemaTpl('collapseGroup', [
getSchemaTpl('switchDefaultValue'),
{
type: 'select',
name: 'value',
label: '默认值',
source: '${options}',
visibleOn: '!data.multiple && typeof this.value !== "undefined"'
},
{
type: 'select',
name: 'value',
label: '默认值',
source: '${options}',
multiple: true,
visibleOn: ' data.multiple && typeof this.value !== "undefined"'
},
{
label: '勾选展示模式',
name: 'selectMode',
type: 'select',
mode: 'inline',
className: 'w-full',
options: [
{
label: '列表形式',
value: 'list'
},
{
label: '表格形式',
value: 'table'
},
{
label: '树形选择形式',
value: 'tree'
},
{
label: '级联选择形式',
value: 'chained'
},
{
label: '关联选择形式',
value: 'associated'
}
title: '基本',
body: [
getSchemaTpl('formItemName', {
required: true
}),
getSchemaTpl('label'),
getSchemaTpl('labelRemark'),
getSchemaTpl('remark'),
getSchemaTpl('placeholder'),
getSchemaTpl('description'),
getSchemaTpl('switch', {
label: '统计数据',
name: 'statistics'
})
]
},
{
name: 'columns',
type: 'combo',
multiple: true,
label: false,
strictMode: false,
addButtonText: '新增一列',
draggable: false,
visibleOn: 'data.selectMode === "table"',
items: [
{
type: 'input-text',
name: 'label',
placeholder: '标题'
},
{
type: 'input-text',
name: 'name',
placeholder: '绑定字段名'
},
title: '左侧选项面板',
body: [
{
label: '展示形式',
name: 'selectMode',
type: 'select',
name: 'type',
placeholder: '类型',
value: 'input-text',
options: [
{
value: 'text',
label: '纯文本'
label: '列表形式',
value: 'list'
},
{
value: 'tpl',
label: '模板'
label: '表格形式',
value: 'table'
},
{
value: 'image',
label: '图片'
},
{
value: 'date',
label: '日期'
},
{
value: 'progress',
label: '进度'
},
{
value: 'status',
label: '状态'
},
{
value: 'mapping',
label: '映射'
},
{
value: 'operation',
label: '操作栏'
label: '树形形式',
value: 'tree'
}
]
}
]
},
{
$ref: 'options',
label: '左边的选项集',
name: 'leftOptions',
visibleOn: 'data.selectMode === "associated"'
},
{
label: '左侧选择形式',
name: 'leftMode',
type: 'select',
mode: 'inline',
className: 'w-full',
visibleOn: 'data.selectMode === "associated"',
options: [
{
label: '列表形式',
value: 'list'
],
onChange: (value: any, origin: any, item: any, form: any) => {
form.setValueByName('options', undefined);
}
},
{
label: '树形选择形式',
value: 'tree'
}
]
},
{
label: '右侧选择形式',
name: 'rightMode',
type: 'select',
mode: 'inline',
className: 'w-full',
visibleOn: 'data.selectMode === "associated"',
options: [
getSchemaTpl('optionControl', {
visibleOn: 'data.selectMode === "list"',
multiple: true
}),
{
label: '列表形式',
value: 'list'
type: 'ae-transferTableControl',
name: 'options',
label: '数据',
visibleOn: 'data.selectMode === "table"',
mode: 'normal'
},
{
label: '树形选择形式',
value: 'tree'
}
]
getSchemaTpl('treeOptionControl', {
visibleOn: 'data.selectMode === "tree"',
}),
getSchemaTpl('switch', {
label: '可检索',
name: 'searchable'
}),
getSchemaTpl('menuTpl', {
label: tipedLabel('模板', '左侧选项渲染模板支持JSX变量使用\\${xx}')
}),
getSchemaTpl('formulaControl', {
label: '标题',
name: 'selectTitle',
type: 'input-text',
inputClassName: 'is-inline '
})
],
},
getSchemaTpl('searchable'),
getSchemaTpl('api', {
label: '检索接口',
name: 'searchApi'
}),
{
label: '查询时勾选展示模式',
name: 'searchResultMode',
type: 'select',
mode: 'inline',
className: 'w-full',
options: [
{
label: '列表形式',
value: 'list'
},
{
label: '表格形式',
value: 'table'
},
{
label: '树形选择形式',
value: 'tree'
},
{
label: '级联选择形式',
value: 'chained'
}
]
},
getSchemaTpl('sortable'),
getSchemaTpl('selectFirst'),
getSchemaTpl('switch', {
label: '是否显示统计数据',
name: 'statistics'
}),
{
label: '左侧的标题文字',
name: 'selectTitle',
type: 'input-text'
},
{
label: '右侧结果的标题文字',
name: 'resultTitle',
type: 'input-text'
},
getSchemaTpl('fieldSet', {
title: '选项',
title: '右侧结果面板',
body: [
{
$ref: 'options',
name: 'options'
type: 'button-group-select',
label: '展示形式',
name: 'resultListModeFollowSelect',
inputClassName: 'items-center',
options: [
{label: '列表形式', value: false},
{label: '跟随左侧', value: true},
],
},
getSchemaTpl('source'),
getSchemaTpl('joinValues'),
getSchemaTpl('delimiter'),
getSchemaTpl('extractValue'),
getSchemaTpl('autoFill')
getSchemaTpl('switch', {
label: tipedLabel(
'可检索',
'查询功能目前只支持根据名称或值来模糊匹配查询'
),
name: 'resultSearchable'
}),
getSchemaTpl('sortable', {
label: '支持排序',
mode: 'horizontal',
horizontal: {
justify: true,
left: 8
},
inputClassName: 'is-inline',
visibleOn: 'data.selectMode === "list" && !data.resultListModeFollowSelect',
}),
getSchemaTpl('menuTpl', {
name: 'valueTpl',
label: tipedLabel('模板', '结果选项渲染模板支持JSX变量使用\\${xx}')
}),
getSchemaTpl('formulaControl', {
label: '标题',
name: 'resultTitle',
type: 'input-text',
inputClassName: 'is-inline '
})
]
})
},
getSchemaTpl('status', {isFormItem: true}),
getSchemaTpl('validation', {tag: ValidatorTag.MultiSelect})
])
},
{
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"'
})
])
])
},
{

View File

@ -0,0 +1,459 @@
/**
* @file Transfer的表格对应选项
*/
import React from 'react';
import { render as amisRender, FormItem } from 'amis';
import { omit } from 'lodash';
import { SchemaApi } from 'amis/lib/Schema';
import { autobind, getSchemaTpl } from 'amis-editor-core';
import cx from 'classnames';
import { tipedLabel } from '../component/BaseControl';
import type { FormControlProps } from 'amis-core';
import type { Option } from 'amis';
interface OptionControlProps extends FormControlProps {
className?: string;
}
interface OptionControlState {
api: SchemaApi;
labelField: string;
valueField: string;
source: 'custom' | 'api' | 'form';
};
function BaseOptionControl(Cmpt: React.JSXElementConstructor<any>) {
return class extends React.Component<OptionControlProps, OptionControlState> {
$comp: string; // 记录一下路径,不再从外部同步内部,只从内部同步外部
internalProps = ['checked', 'editing'];
constructor(props: OptionControlProps) {
super(props);
this.state = {
api: props.data.source,
labelField: props.data.labelField,
valueField: props.data.valueField,
source: props.data.source ? 'api' : 'custom'
};
this.handleSourceChange = this.handleSourceChange.bind(this);
this.handleAPIChange = this.handleAPIChange.bind(this);
this.handleLableFieldChange = this.handleLableFieldChange.bind(this);
this.handleValueFieldChange = this.handleValueFieldChange.bind(this);
this.onChange = this.onChange.bind(this);
}
/**
* options字段的统一出口
*/
onChange() {
const { source } = this.state;
const { onBulkChange } = this.props;
const data: Partial<OptionControlProps> = {
source: undefined,
options: undefined,
labelField: undefined,
valueField: undefined
};
if (source === 'api') {
const { api, labelField, valueField } = this.state;
data.source = api;
data.labelField = labelField;
data.valueField = valueField;
}
onBulkChange && onBulkChange(data);
return;
}
/**
*
*/
handleSourceChange(source: 'custom' | 'api' | 'form') {
this.setState({ source: source }, this.onChange);
}
handleAPIChange(source: SchemaApi) {
this.setState({ api: source }, this.onChange);
}
handleLableFieldChange(labelField: string) {
this.setState({ labelField }, this.onChange);
}
handleValueFieldChange(valueField: string) {
this.setState({ valueField }, this.onChange);
}
buildBatchAddSchema() {
return {
type: 'action',
actionType: 'dialog',
label: '批量添加',
dialog: {
title: '批量添加选项',
headerClassName: 'font-bold',
closeOnEsc: true,
closeOnOutside: false,
showCloseButton: true,
body: [
{
type: 'alert',
level: 'warning',
body: [
{
type: 'tpl',
tpl: '每个选项单列一行,将所有值不重复的项加为新的选项;<br/>每行可通过空格来分别设置label和value,例:"张三 zhangsan"'
}
],
showIcon: true,
className: 'mb-2.5'
},
{
type: 'form',
wrapWithPanel: false,
mode: 'normal',
wrapperComponent: 'div',
resetAfterSubmit: true,
autoFocus: true,
preventEnterSubmit: true,
horizontal: {
left: 0,
right: 12
},
body: [
{
name: 'batchOption',
type: 'textarea',
label: '',
placeholder: '请输入选项内容',
trimContents: true,
minRows: 10,
maxRows: 50,
required: true
}
]
}
]
}
};
}
renderHeader() {
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'
}
] as Array<{
label: string;
value: 'custom' | 'api' | 'form';
}>
).map(item => ({
...item,
onClick: () => this.handleSourceChange(item.value)
}));
return (
<header className="ae-OptionControl-header">
<label className={cx(`${classPrefix}Form-label`)}>
{label || ''}
{labelRemark
? render('label-remark', {
type: 'remark',
icon: labelRemark.icon || 'warning-mark',
tooltip: labelRemark,
className: cx(`Form-lableRemark`, labelRemark?.className),
useMobileUI,
container: popOverContainer
? popOverContainer
: env && env.getModalContainer
? env.getModalContainer
: undefined
})
: null}
</label>
<div>
{render(
'validation-control-addBtn',
{
type: 'dropdown-button',
level: 'link',
size: 'sm',
label: '${selected}',
align: 'right',
closeOnClick: true,
closeOnOutside: true,
buttons: optionSourceList
},
{
popOverContainer: null,
data: {
selected: optionSourceList.find(item => item.value === source)!
.label
}
}
)}
</div>
</header>
);
}
renderApiPanel() {
const { render } = this.props;
const { source, api, labelField, valueField } = this.state;
if (source !== 'api') {
return null;
}
return render(
'api',
getSchemaTpl('apiControl', {
label: '接口',
name: 'source',
className: 'ae-ExtendMore',
visibleOn: 'data.autoComplete !== false',
value: api,
onChange: this.handleAPIChange,
footer: [
{
label: tipedLabel(
'显示字段',
'选项文本对应的数据字段,多字段合并请通过模板配置'
),
type: 'input-text',
name: 'labelField',
value: labelField,
placeholder: '选项文本对应的字段',
onChange: this.handleLableFieldChange
},
{
label: '值字段',
type: 'input-text',
name: 'valueField',
value: valueField,
placeholder: '值对应的字段',
onChange: this.handleValueFieldChange
}
]
})
);
}
render() {
const { source, api, labelField, valueField } = this.state;
const { className } = this.props;
const cmptProps = {
...this.props,
data: {
api,
labelField,
valueField,
...this.props?.data
},
}
return (
<div className={cx('ae-OptionControl', className)}>
{this.renderHeader()}
{source === 'custom' ? (
<Cmpt {...cmptProps} />
) : null}
{this.renderApiPanel()}
</div>
);
}
}
}
const renderInput = (
name: string,
placeholder: string,
required: boolean = true
) => {
return {
type: 'input-text',
name,
placeholder: placeholder,
required
}
}
export default class TransferTableOption extends React.Component<OptionControlProps, {}> {
addColumns() {
const { columns = [{ type: 'text' }] } = this.props.data;
return {
type: 'action',
actionType: 'dialog',
label: '添加表格列',
level: 'enhance',
dialog: {
title: '设置表格列选项',
headerClassName: 'font-bold',
closeOnEsc: true,
closeOnOutside: false,
showCloseButton: true,
body: [
{
name: 'columns',
type: 'combo',
multiple: true,
label: false,
strictMode: false,
addButtonText: '新增一列',
draggable: false,
value: columns,
onChange: (value: Array<Option>) => this.handleColumnsChange(value),
items: [
{
type: 'input-text',
name: 'label',
placeholder: '标题'
},
{
type: 'input-text',
name: 'name',
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: 'operation',
label: '操作栏'
}
]
}
]
}
]
}
};
}
addRows() {
const { columns = [], options = [{}] } = this.props.data;
return {
type: 'tooltip-wrapper',
tooltip: '需设置表格列后,才能设置表格行',
tooltipTheme: 'dark',
placement: 'top',
tooltipStyle: {
fontSize: '12px'
},
className: 'ae-formItemControl-label-tip',
body: [{
type: 'action',
actionType: 'dialog',
label: '添加表格行',
level: 'enhance',
disabled: columns && columns.length === 0,
block: true,
dialog: {
title: '设置表格行选项',
headerClassName: 'font-bold',
closeOnEsc: true,
closeOnOutside: false,
showCloseButton: true,
size: columns.length >= 6 ? 'md' : '',
body: [{
name: 'options',
type: 'combo',
multiple: true,
draggable: true,
addButtonText: '新增',
value: options,
onChange: (value: Array<Option>) => this.handleRowsChange(value),
items: [
...columns.map((item: Option) => renderInput(item.name, item.label ?? '')),
renderInput('value', '值', true)
]
}]
}
}]
};
}
@autobind
handleColumnsChange(value: Array<Option>) {
const { data } = this.props;
const { onBulkChange } = this.props;
data.columns = value.map(item => omit(item, 'id'));
onBulkChange && onBulkChange(data);
}
@autobind
handleRowsChange(value: Array<Option>) {
const { data } = this.props;
const { onBulkChange } = this.props;
data.options = value;
onBulkChange && onBulkChange(data);
}
render() {
return (
<div className='ae-OptionControl-footer'>
{amisRender(this.addColumns())}
{amisRender(this.addRows())}
</div>)
}
}
const TransferTableControl = BaseOptionControl(TransferTableOption);
@FormItem({
type: 'ae-transferTableControl',
renderLabel: false
})
export class TransferTableControlRenderer extends TransferTableControl { }