diff --git a/docs/zh-CN/components/form/file.md b/docs/zh-CN/components/form/file.md index c8ad88a2f..beed2f5a0 100755 --- a/docs/zh-CN/components/form/file.md +++ b/docs/zh-CN/components/form/file.md @@ -143,6 +143,31 @@ order: 21 这样上传成功后,会把接口中的 `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) 中的配置以外,还支持下面一些配置 diff --git a/docs/zh-CN/components/form/image.md b/docs/zh-CN/components/form/image.md index 864876ead..67da62eba 100755 --- a/docs/zh-CN/components/form/image.md +++ b/docs/zh-CN/components/form/image.md @@ -156,6 +156,31 @@ order: 27 这样上传成功后,会把接口中的 `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) 中的配置以外,还支持下面一些配置 diff --git a/docs/zh-CN/components/form/options.md b/docs/zh-CN/components/form/options.md index 129896545..a4a5ebb43 100755 --- a/docs/zh-CN/components/form/options.md +++ b/docs/zh-CN/components/form/options.md @@ -1265,12 +1265,13 @@ order: 2 ## 自动填充 autoFill -一些选择器组件,支持配置`autoFill`,将当前已选中的选项的某个字段的值,自动填充到表单中某个表单项中,**只在单选时有效**,支持[数据映射](../../../docs/concepts/data-mapping) +一些选择器组件,支持配置`autoFill`,将当前已选中的选项的某个字段的值,自动填充到表单中某个表单项中,支持[数据映射](../../../docs/concepts/data-mapping) ```schema: scope="body" { "type": "form", "api": "https://3xsw4ap8wah59.cfc-execute.bj.baidubce.com/api/amis-mock/mock2/form/saveForm", + "debug": true, "controls": [ { "type": "select", @@ -1279,6 +1280,7 @@ order: 2 "autoFill": { "option": "${label}" }, + "clearable": true, "options": [ { "label": "Option A", @@ -1301,6 +1303,41 @@ order: 2 上例中我们配置了`"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。 ## 属性表 diff --git a/src/components/Select.tsx b/src/components/Select.tsx index 6f751a6e9..38269d7ea 100644 --- a/src/components/Select.tsx +++ b/src/components/Select.tsx @@ -807,6 +807,7 @@ export class Select extends React.Component { this.handleChange(item); }} disabled={item.disabled} + size="sm" > {item.disabled ? item[labelField] @@ -867,6 +868,7 @@ export class Select extends React.Component { checked={checkedPartial} partial={checkedPartial && !checkedAll} onChange={this.toggleCheckAll} + size="sm" > {__(checkAllLabel)} @@ -874,7 +876,11 @@ export class Select extends React.Component { ) : null}
- Placeholder + {multiple ? ( + Placeholder + ) : ( + Placeholder + )}
{creatable && !disabled ? ( diff --git a/src/renderers/Form/File.tsx b/src/renderers/Form/File.tsx index da53627ba..7151f346d 100644 --- a/src/renderers/Form/File.tsx +++ b/src/renderers/Form/File.tsx @@ -605,7 +605,7 @@ export default class FileControl extends React.Component { return; } - const {translate: __, multiple, autoFill, onBulkChange} = this.props; + const {translate: __} = this.props; const nameField = this.props.nameField || 'name'; const file = find( this.state.files, @@ -647,17 +647,7 @@ export default class FileControl extends React.Component { error: error ? error : null, files: files }, - () => { - // todo 这个逻辑应该移到 onChange 里面去,因为这个时候并不一定修改了表单项的值。 - const sendTo = - !multiple && - autoFill && - !isEmpty(autoFill) && - dataMapping(autoFill, obj || {}); - sendTo && onBulkChange(sendTo); - - this.tick(); - } + this.tick ); }, progress => { @@ -816,7 +806,9 @@ export default class FileControl extends React.Component { valueField, delimiter, resetValue, - asBlob + asBlob, + autoFill, + onBulkChange } = this.props; const files = this.state.files.filter( @@ -841,6 +833,18 @@ export default class FileControl extends React.Component { } onChange((this.emitValue = value), undefined, changeImmediately); + + if (!isEmpty(autoFill)) { + const toSync = dataMapping( + autoFill, + multiple + ? { + items: files + } + : files[0] + ); + onBulkChange(toSync); + } } uploadFile( diff --git a/src/renderers/Form/Image.tsx b/src/renderers/Form/Image.tsx index f83269c0d..f1904c5f6 100644 --- a/src/renderers/Form/Image.tsx +++ b/src/renderers/Form/Image.tsx @@ -571,7 +571,6 @@ export default class ImageControl extends React.Component< } tick() { - const {multiple, autoFill, onBulkChange} = this.props; if (this.current || !this.state.uploading) { return; } @@ -632,17 +631,7 @@ export default class ImageControl extends React.Component< { files: (this.files = files) }, - () => { - // todo 这个逻辑应该移到 onChange 里面去,因为这个时候并不一定修改了表单项的值。 - const sendTo = - !multiple && - autoFill && - !isEmpty(autoFill) && - dataMapping(autoFill, newFile || {}); - sendTo && onBulkChange(sendTo); - - this.tick(); - } + this.tick ); }, progress => { @@ -734,7 +723,9 @@ export default class ImageControl extends React.Component< joinValues, extractValue, delimiter, - valueField + valueField, + autoFill, + onBulkChange } = this.props; const files = this.files.filter( @@ -762,6 +753,18 @@ export default class ImageControl extends React.Component< } onChange((this.emitValue = newValue || ''), undefined, changeImmediately); + + if (!isEmpty(autoFill)) { + const toSync = dataMapping( + autoFill, + multiple + ? { + items: files + } + : files[0] + ); + onBulkChange(toSync); + } } handleSelect() { diff --git a/src/store/formItem.ts b/src/store/formItem.ts index f3141ee58..0d0cc6e33 100644 --- a/src/store/formItem.ts +++ b/src/store/formItem.ts @@ -391,6 +391,7 @@ export const FormItemStore = StoreNode.named('FormItemStore') self.options = options; syncOptions(originOptions); let selectedOptions; + let skipAyncAutoFill = false; if ( self.selectFirst && @@ -422,10 +423,11 @@ export const FormItemStore = StoreNode.named('FormItemStore') onChange(value); } else { changeValue(value, !form.inited); + skipAyncAutoFill = true; // changeValue 里面本来就会调用 syncAutoFill 所以跳过 } } - syncAutoFill(self.value, !form.inited); + skipAyncAutoFill || syncAutoFill(self.value, !form.inited); } let loadCancel: Function | null = null; @@ -799,29 +801,35 @@ export const FormItemStore = StoreNode.named('FormItemStore') value: any = self.value, isPrintine: boolean = false ) { - if ( - !self.multiple && - self.autoFill && - !isEmpty(self.autoFill) && - self.options.length - ) { + if (self.autoFill && !isEmpty(self.autoFill) && self.options.length) { const selectedOptions = self.getSelectedOptions(value); - if (selectedOptions.length !== 1) { - return; - } - const toSync = dataMapping( self.autoFill, - createObject( - { - ancestors: getTreeAncestors( - self.filteredOptions, - selectedOptions[0], - true + self.multiple + ? { + items: selectedOptions.map(item => + createObject( + { + ancestors: getTreeAncestors( + self.filteredOptions, + item, + true + ) + }, + item + ) + ) + } + : createObject( + { + ancestors: getTreeAncestors( + self.filteredOptions, + selectedOptions[0], + true + ) + }, + selectedOptions[0] ) - }, - selectedOptions[0] - ) ); Object.keys(toSync).forEach(key => { const value = toSync[key];