autoFill 支持多选

This commit is contained in:
2betop 2021-05-08 17:16:48 +08:00
parent 845b7c266a
commit c702f7bb3f
7 changed files with 156 additions and 48 deletions

View File

@ -143,6 +143,31 @@ order: 21
这样上传成功后,会把接口中的 `url` 变量,赋值给 `myUrl` 变量 这样上传成功后,会把接口中的 `url` 变量,赋值给 `myUrl` 变量
**多选模式**
当表单项为多选模式时,不能再直接取选项中的值了,而是通过 `items` 变量来取,通过它可以获取当前选中的选项集合。
```schema: scope="body"
{
"type": "form",
"debug": true,
"api": "https://3xsw4ap8wah59.cfc-execute.bj.baidubce.com/api/amis-mock/mock2/form/saveForm",
"controls": [
{
"type": "file",
"name": "file",
"label": "File",
"multiple": true,
"receiver": "https://3xsw4ap8wah59.cfc-execute.bj.baidubce.com/api/amis-mock/upload/file",
"autoFill": {
"myUrl": "${items|pick:url}",
"lastUrl": "${items|last|pick:url}"
}
}
]
}
```
## 属性表 ## 属性表
除了支持 [普通表单项属性表](./formitem#%E5%B1%9E%E6%80%A7%E8%A1%A8) 中的配置以外,还支持下面一些配置 除了支持 [普通表单项属性表](./formitem#%E5%B1%9E%E6%80%A7%E8%A1%A8) 中的配置以外,还支持下面一些配置

View File

@ -156,6 +156,31 @@ order: 27
这样上传成功后,会把接口中的 `url` 变量,赋值给 `myUrl` 变量 这样上传成功后,会把接口中的 `url` 变量,赋值给 `myUrl` 变量
**多选模式**
当表单项为多选模式时,不能再直接取选项中的值了,而是通过 `items` 变量来取,通过它可以获取当前选中的选项集合。
```schema: scope="body"
{
"type": "form",
"debug": true,
"api": "https://3xsw4ap8wah59.cfc-execute.bj.baidubce.com/api/amis-mock/mock2/form/saveForm",
"controls": [
{
"type": "image",
"name": "image",
"label": "image",
"multiple": true,
"receiver": "https://3xsw4ap8wah59.cfc-execute.bj.baidubce.com/api/amis-mock/upload/file",
"autoFill": {
"myUrl": "${items|pick:url}",
"lastUrl": "${items|last|pick:url}"
}
}
]
}
```
## 属性表 ## 属性表
除了支持 [普通表单项属性表](./formitem#%E5%B1%9E%E6%80%A7%E8%A1%A8) 中的配置以外,还支持下面一些配置 除了支持 [普通表单项属性表](./formitem#%E5%B1%9E%E6%80%A7%E8%A1%A8) 中的配置以外,还支持下面一些配置

View File

@ -1265,12 +1265,13 @@ order: 2
## 自动填充 autoFill ## 自动填充 autoFill
一些选择器组件,支持配置`autoFill`,将当前已选中的选项的某个字段的值,自动填充到表单中某个表单项中,**只在单选时有效**支持[数据映射](../../../docs/concepts/data-mapping) 一些选择器组件,支持配置`autoFill`,将当前已选中的选项的某个字段的值,自动填充到表单中某个表单项中,支持[数据映射](../../../docs/concepts/data-mapping)
```schema: scope="body" ```schema: scope="body"
{ {
"type": "form", "type": "form",
"api": "https://3xsw4ap8wah59.cfc-execute.bj.baidubce.com/api/amis-mock/mock2/form/saveForm", "api": "https://3xsw4ap8wah59.cfc-execute.bj.baidubce.com/api/amis-mock/mock2/form/saveForm",
"debug": true,
"controls": [ "controls": [
{ {
"type": "select", "type": "select",
@ -1279,6 +1280,7 @@ order: 2
"autoFill": { "autoFill": {
"option": "${label}" "option": "${label}"
}, },
"clearable": true,
"options": [ "options": [
{ {
"label": "Option A", "label": "Option A",
@ -1301,6 +1303,41 @@ order: 2
上例中我们配置了`"autoFill": {"option": "${label}"}`,表示将选中项中的`label`的值,自动填充到当前表单项中`name`为`option`的文本框中。 上例中我们配置了`"autoFill": {"option": "${label}"}`,表示将选中项中的`label`的值,自动填充到当前表单项中`name`为`option`的文本框中。
**多选模式**
当表单项为多选模式时,不能再直接取选项中的值了,而是通过 `items` 变量来取,通过它可以获取当前选中的选项集合。
```schema: scope="body"
{
"type": "form",
"api": "https://3xsw4ap8wah59.cfc-execute.bj.baidubce.com/api/amis-mock/mock2/form/saveForm",
"debug": true,
"controls": [
{
"type": "select",
"label": "选项",
"name": "select",
"autoFill": {
"options": "${items|pick:label}",
"firstOption": "${items|first|pick:label}"
},
"multiple": true,
"clearable": true,
"options": [
{
"label": "Option A",
"value": "a"
},
{
"label": "Option B",
"value": "b"
}
]
}
]
}
```
支持该配置项的有ButtonGroup、List、NestedSelect、Picker、Radios、Select。 支持该配置项的有ButtonGroup、List、NestedSelect、Picker、Radios、Select。
## 属性表 ## 属性表

View File

@ -807,6 +807,7 @@ export class Select extends React.Component<SelectProps, SelectState> {
this.handleChange(item); this.handleChange(item);
}} }}
disabled={item.disabled} disabled={item.disabled}
size="sm"
> >
{item.disabled {item.disabled
? item[labelField] ? item[labelField]
@ -867,6 +868,7 @@ export class Select extends React.Component<SelectProps, SelectState> {
checked={checkedPartial} checked={checkedPartial}
partial={checkedPartial && !checkedAll} partial={checkedPartial && !checkedAll}
onChange={this.toggleCheckAll} onChange={this.toggleCheckAll}
size="sm"
> >
{__(checkAllLabel)} {__(checkAllLabel)}
</Checkbox> </Checkbox>
@ -874,7 +876,11 @@ export class Select extends React.Component<SelectProps, SelectState> {
) : null} ) : null}
<div ref={this.menuItemRef} className={cx('Select-option invisible')}> <div ref={this.menuItemRef} className={cx('Select-option invisible')}>
{multiple ? (
<Checkbox size="sm">Placeholder</Checkbox>
) : (
<span>Placeholder</span> <span>Placeholder</span>
)}
</div> </div>
{creatable && !disabled ? ( {creatable && !disabled ? (

View File

@ -605,7 +605,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
return; return;
} }
const {translate: __, multiple, autoFill, onBulkChange} = this.props; const {translate: __} = this.props;
const nameField = this.props.nameField || 'name'; const nameField = this.props.nameField || 'name';
const file = find( const file = find(
this.state.files, this.state.files,
@ -647,17 +647,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
error: error ? error : null, error: error ? error : null,
files: files files: files
}, },
() => { this.tick
// todo 这个逻辑应该移到 onChange 里面去,因为这个时候并不一定修改了表单项的值。
const sendTo =
!multiple &&
autoFill &&
!isEmpty(autoFill) &&
dataMapping(autoFill, obj || {});
sendTo && onBulkChange(sendTo);
this.tick();
}
); );
}, },
progress => { progress => {
@ -816,7 +806,9 @@ export default class FileControl extends React.Component<FileProps, FileState> {
valueField, valueField,
delimiter, delimiter,
resetValue, resetValue,
asBlob asBlob,
autoFill,
onBulkChange
} = this.props; } = this.props;
const files = this.state.files.filter( const files = this.state.files.filter(
@ -841,6 +833,18 @@ export default class FileControl extends React.Component<FileProps, FileState> {
} }
onChange((this.emitValue = value), undefined, changeImmediately); onChange((this.emitValue = value), undefined, changeImmediately);
if (!isEmpty(autoFill)) {
const toSync = dataMapping(
autoFill,
multiple
? {
items: files
}
: files[0]
);
onBulkChange(toSync);
}
} }
uploadFile( uploadFile(

View File

@ -571,7 +571,6 @@ export default class ImageControl extends React.Component<
} }
tick() { tick() {
const {multiple, autoFill, onBulkChange} = this.props;
if (this.current || !this.state.uploading) { if (this.current || !this.state.uploading) {
return; return;
} }
@ -632,17 +631,7 @@ export default class ImageControl extends React.Component<
{ {
files: (this.files = files) files: (this.files = files)
}, },
() => { this.tick
// todo 这个逻辑应该移到 onChange 里面去,因为这个时候并不一定修改了表单项的值。
const sendTo =
!multiple &&
autoFill &&
!isEmpty(autoFill) &&
dataMapping(autoFill, newFile || {});
sendTo && onBulkChange(sendTo);
this.tick();
}
); );
}, },
progress => { progress => {
@ -734,7 +723,9 @@ export default class ImageControl extends React.Component<
joinValues, joinValues,
extractValue, extractValue,
delimiter, delimiter,
valueField valueField,
autoFill,
onBulkChange
} = this.props; } = this.props;
const files = this.files.filter( const files = this.files.filter(
@ -762,6 +753,18 @@ export default class ImageControl extends React.Component<
} }
onChange((this.emitValue = newValue || ''), undefined, changeImmediately); onChange((this.emitValue = newValue || ''), undefined, changeImmediately);
if (!isEmpty(autoFill)) {
const toSync = dataMapping(
autoFill,
multiple
? {
items: files
}
: files[0]
);
onBulkChange(toSync);
}
} }
handleSelect() { handleSelect() {

View File

@ -391,6 +391,7 @@ export const FormItemStore = StoreNode.named('FormItemStore')
self.options = options; self.options = options;
syncOptions(originOptions); syncOptions(originOptions);
let selectedOptions; let selectedOptions;
let skipAyncAutoFill = false;
if ( if (
self.selectFirst && self.selectFirst &&
@ -422,10 +423,11 @@ export const FormItemStore = StoreNode.named('FormItemStore')
onChange(value); onChange(value);
} else { } else {
changeValue(value, !form.inited); changeValue(value, !form.inited);
skipAyncAutoFill = true; // changeValue 里面本来就会调用 syncAutoFill 所以跳过
} }
} }
syncAutoFill(self.value, !form.inited); skipAyncAutoFill || syncAutoFill(self.value, !form.inited);
} }
let loadCancel: Function | null = null; let loadCancel: Function | null = null;
@ -799,20 +801,26 @@ export const FormItemStore = StoreNode.named('FormItemStore')
value: any = self.value, value: any = self.value,
isPrintine: boolean = false isPrintine: boolean = false
) { ) {
if ( if (self.autoFill && !isEmpty(self.autoFill) && self.options.length) {
!self.multiple &&
self.autoFill &&
!isEmpty(self.autoFill) &&
self.options.length
) {
const selectedOptions = self.getSelectedOptions(value); const selectedOptions = self.getSelectedOptions(value);
if (selectedOptions.length !== 1) {
return;
}
const toSync = dataMapping( const toSync = dataMapping(
self.autoFill, self.autoFill,
self.multiple
? {
items: selectedOptions.map(item =>
createObject( createObject(
{
ancestors: getTreeAncestors(
self.filteredOptions,
item,
true
)
},
item
)
)
}
: createObject(
{ {
ancestors: getTreeAncestors( ancestors: getTreeAncestors(
self.filteredOptions, self.filteredOptions,