improve select
This commit is contained in:
parent
15fca2b009
commit
9cc5363f49
@ -5,6 +5,7 @@ import {
|
|||||||
Schema,
|
Schema,
|
||||||
useFieldSchema,
|
useFieldSchema,
|
||||||
observer,
|
observer,
|
||||||
|
SchemaExpressionScopeContext,
|
||||||
} from '@formily/react';
|
} from '@formily/react';
|
||||||
import { SchemaRenderer, useDesignable } from '../DesignableSchemaField';
|
import { SchemaRenderer, useDesignable } from '../DesignableSchemaField';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
@ -40,6 +41,8 @@ function useDefaultValues() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const Form: any = observer((props: any) => {
|
export const Form: any = observer((props: any) => {
|
||||||
|
const scope = useContext(SchemaExpressionScopeContext);
|
||||||
|
|
||||||
const { useValues = useDefaultValues } = props;
|
const { useValues = useDefaultValues } = props;
|
||||||
const values = useValues();
|
const values = useValues();
|
||||||
const form = useMemo(() => {
|
const form = useMemo(() => {
|
||||||
@ -67,6 +70,8 @@ export const Form: any = observer((props: any) => {
|
|||||||
return (
|
return (
|
||||||
<div ref={ref} className={'nb-form'}>
|
<div ref={ref} className={'nb-form'}>
|
||||||
<SchemaRenderer
|
<SchemaRenderer
|
||||||
|
scope={scope}
|
||||||
|
// components={options.components}
|
||||||
onRefresh={(subSchema: Schema) => {
|
onRefresh={(subSchema: Schema) => {
|
||||||
designableSchema.properties = subSchema.properties;
|
designableSchema.properties = subSchema.properties;
|
||||||
refresh();
|
refresh();
|
||||||
|
@ -11,7 +11,10 @@ group:
|
|||||||
|
|
||||||
# Select - 选择器
|
# Select - 选择器
|
||||||
|
|
||||||
## 基本用法
|
|
||||||
|
## Select
|
||||||
|
|
||||||
|
### 单选
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
@ -70,7 +73,7 @@ export default () => {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
## 多选
|
### 多选
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
@ -134,7 +137,7 @@ export default () => {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
## 分组
|
### 分组
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
@ -200,7 +203,11 @@ export default () => {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
## 值为对象
|
## Select.Object
|
||||||
|
|
||||||
|
选项值为 Object 类型
|
||||||
|
|
||||||
|
### 单选
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
@ -233,12 +240,14 @@ const schema = {
|
|||||||
'x-component': 'Select.Object',
|
'x-component': 'Select.Object',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
placeholder: 'please enter',
|
placeholder: 'please enter',
|
||||||
labelField: 'title',
|
// mode: 'tags',
|
||||||
valueField: 'id',
|
fieldNames: {
|
||||||
labelInValue: true,
|
label: 'title',
|
||||||
|
value: 'id',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
'x-reactions': {
|
'x-reactions': {
|
||||||
target: 'name2',
|
target: 'read',
|
||||||
fulfill: {
|
fulfill: {
|
||||||
state: {
|
state: {
|
||||||
value: '{{$self.value}}',
|
value: '{{$self.value}}',
|
||||||
@ -250,16 +259,17 @@ const schema = {
|
|||||||
interface: 'select',
|
interface: 'select',
|
||||||
type: 'string',
|
type: 'string',
|
||||||
title: `阅读模式`,
|
title: `阅读模式`,
|
||||||
required: true,
|
|
||||||
enum: dataSource,
|
enum: dataSource,
|
||||||
'x-read-pretty': true,
|
'x-read-pretty': true,
|
||||||
'x-decorator': 'FormItem',
|
'x-decorator': 'FormItem',
|
||||||
'x-component': 'Select.Object',
|
'x-component': 'Select.Object',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
placeholder: 'please enter',
|
placeholder: 'please enter',
|
||||||
labelField: 'title',
|
// mode: 'tags',
|
||||||
valueField: 'id',
|
fieldNames: {
|
||||||
labelInValue: true,
|
label: 'title',
|
||||||
|
value: 'id',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -270,4 +280,282 @@ export default () => {
|
|||||||
<SchemaRenderer schema={schema} />
|
<SchemaRenderer schema={schema} />
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### 多选
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import React from 'react';
|
||||||
|
import { SchemaRenderer } from '../';
|
||||||
|
|
||||||
|
const dataSource = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
title: '标题1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
title: '标题2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
title: '标题3',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const schema = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
input: {
|
||||||
|
interface: 'select',
|
||||||
|
type: 'string',
|
||||||
|
title: `编辑模式`,
|
||||||
|
enum: dataSource,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Select.Object',
|
||||||
|
'x-component-props': {
|
||||||
|
placeholder: 'please enter',
|
||||||
|
mode: 'tags',
|
||||||
|
fieldNames: {
|
||||||
|
label: 'title',
|
||||||
|
value: 'id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-reactions': {
|
||||||
|
target: 'read',
|
||||||
|
fulfill: {
|
||||||
|
state: {
|
||||||
|
value: '{{$self.value}}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
read: {
|
||||||
|
interface: 'select',
|
||||||
|
type: 'string',
|
||||||
|
title: `阅读模式`,
|
||||||
|
enum: dataSource,
|
||||||
|
'x-read-pretty': true,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Select.Object',
|
||||||
|
'x-component-props': {
|
||||||
|
placeholder: 'please enter',
|
||||||
|
mode: 'tags',
|
||||||
|
fieldNames: {
|
||||||
|
label: 'title',
|
||||||
|
value: 'id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
return (
|
||||||
|
<SchemaRenderer schema={schema} />
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Select.Drawer
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import React from 'react';
|
||||||
|
import { SchemaRenderer } from '../';
|
||||||
|
import { useSelect } from './';
|
||||||
|
|
||||||
|
console.log({ useSelect })
|
||||||
|
|
||||||
|
const dataSource = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
title: '标题1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
title: '标题2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
title: '标题3',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
function useValues() {
|
||||||
|
return {
|
||||||
|
table: dataSource,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const schema = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
input: {
|
||||||
|
interface: 'select',
|
||||||
|
type: 'string',
|
||||||
|
title: `编辑模式`,
|
||||||
|
enum: dataSource,
|
||||||
|
default: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
title: '标题1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
title: '标题2',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Select.Drawer',
|
||||||
|
'x-component-props': {
|
||||||
|
placeholder: 'please enter',
|
||||||
|
mode: 'tags',
|
||||||
|
fieldNames: {
|
||||||
|
label: 'title',
|
||||||
|
value: 'id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-reactions': {
|
||||||
|
target: 'read',
|
||||||
|
fulfill: {
|
||||||
|
state: {
|
||||||
|
value: '{{$self.value}}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
options: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Select.Options',
|
||||||
|
properties: {
|
||||||
|
form: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Form',
|
||||||
|
'x-component-props': {
|
||||||
|
useValues: '{{ useValues }}',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
table: {
|
||||||
|
type: 'array',
|
||||||
|
'x-component': 'Table',
|
||||||
|
properties: {
|
||||||
|
actionbar: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Table.ActionBar',
|
||||||
|
'x-component-props': {
|
||||||
|
align: 'bottom',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
action: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-component-props': {
|
||||||
|
useAction: '{{ useSelect }}',
|
||||||
|
},
|
||||||
|
title: '确定',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
column1: {
|
||||||
|
type: 'void',
|
||||||
|
title: '标题',
|
||||||
|
'x-component': 'Table.Column',
|
||||||
|
'x-component-props': {
|
||||||
|
// title: 'z1',
|
||||||
|
},
|
||||||
|
// 'x-designable-bar': 'Table.Column.DesignableBar',
|
||||||
|
properties: {
|
||||||
|
title: {
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
'x-read-pretty': true,
|
||||||
|
'x-decorator-props': {
|
||||||
|
feedbackLayout: 'popover',
|
||||||
|
},
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
read: {
|
||||||
|
interface: 'select',
|
||||||
|
type: 'string',
|
||||||
|
title: `阅读模式`,
|
||||||
|
enum: dataSource,
|
||||||
|
default: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
title: '标题1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
title: '标题2',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'x-read-pretty': true,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Select.Drawer',
|
||||||
|
'x-component-props': {
|
||||||
|
placeholder: 'please enter',
|
||||||
|
mode: 'tags',
|
||||||
|
fieldNames: {
|
||||||
|
label: 'title',
|
||||||
|
value: 'id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
option: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Select.OptionTag',
|
||||||
|
properties: {
|
||||||
|
form: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Form',
|
||||||
|
properties: {
|
||||||
|
input: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
return (
|
||||||
|
<SchemaRenderer scope={{ useSelect, useValues }} schema={schema} />
|
||||||
|
);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<Select />
|
||||||
|
<Select.Object />
|
||||||
|
<Select.Drawer>
|
||||||
|
<Select.Options>
|
||||||
|
<Table />
|
||||||
|
<Action />
|
||||||
|
<Select.Options>
|
||||||
|
<Select.ItemDetails>
|
||||||
|
<Form/>
|
||||||
|
</Select.ItemDetails>
|
||||||
|
<Select.Drawer>
|
||||||
|
|
||||||
|
<Action />
|
||||||
|
|
||||||
|
<Action>
|
||||||
|
<Drawer />
|
||||||
|
</Action>
|
||||||
|
-->
|
||||||
|
@ -1,38 +1,50 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { connect, mapReadPretty, mapProps, useField } from '@formily/react';
|
import {
|
||||||
import { Select as AntdSelect, Tag } from 'antd';
|
connect,
|
||||||
|
mapReadPretty,
|
||||||
|
mapProps,
|
||||||
|
useField,
|
||||||
|
observer,
|
||||||
|
RecursionField,
|
||||||
|
useFieldSchema,
|
||||||
|
} from '@formily/react';
|
||||||
|
import { Drawer, Select as AntdSelect, Tag } from 'antd';
|
||||||
import { PreviewText } from '@formily/antd';
|
import { PreviewText } from '@formily/antd';
|
||||||
import { LoadingOutlined } from '@ant-design/icons';
|
import { LoadingOutlined } from '@ant-design/icons';
|
||||||
import { SelectProps } from 'antd/lib/select';
|
import { SelectProps } from 'antd/lib/select';
|
||||||
import { isArr, isValid } from '@formily/shared';
|
import { isArr, isValid, toArr } from '@formily/shared';
|
||||||
import { Field } from '@formily/core/esm/models/Field';
|
import { useState } from 'react';
|
||||||
import { useAction } from '../../state';
|
import { useDesignable } from '../DesignableSchemaField';
|
||||||
import { Display } from '../display';
|
import { createContext } from 'react';
|
||||||
import { useRequest } from 'ahooks';
|
import { useContext } from 'react';
|
||||||
import uniq from 'lodash/uniq';
|
import { useTableContext } from '../table';
|
||||||
|
|
||||||
type ComposedSelect = React.FC<SelectProps<any>> & {
|
export const Select: any = connect(
|
||||||
Object?: React.FC;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Select: ComposedSelect = connect(
|
|
||||||
(props) => {
|
(props) => {
|
||||||
const { options = [], ...others } = props;
|
const { options = [], ...others } = props;
|
||||||
return <AntdSelect {...others}>
|
return (
|
||||||
{options.map((option: any, key: any) => {
|
<AntdSelect {...others}>
|
||||||
if (option.children) {
|
{options.map((option: any, key: any) => {
|
||||||
return (
|
if (option.children) {
|
||||||
<AntdSelect.OptGroup key={key} label={option.label}>
|
return (
|
||||||
{option.children.map((child: any, childKey: any) => (
|
<AntdSelect.OptGroup key={key} label={option.label}>
|
||||||
<AntdSelect.Option key={`${key}-${childKey}`} {...child}>{child.label}</AntdSelect.Option>
|
{option.children.map((child: any, childKey: any) => (
|
||||||
))}
|
<AntdSelect.Option key={`${key}-${childKey}`} {...child}>
|
||||||
</AntdSelect.OptGroup>
|
{child.label}
|
||||||
)
|
</AntdSelect.Option>
|
||||||
} else {
|
))}
|
||||||
return <AntdSelect.Option key={key} {...option}>{option.label}</AntdSelect.Option>
|
</AntdSelect.OptGroup>
|
||||||
}
|
);
|
||||||
})}
|
} else {
|
||||||
</AntdSelect>
|
return (
|
||||||
|
<AntdSelect.Option key={key} {...option}>
|
||||||
|
{option.label}
|
||||||
|
</AntdSelect.Option>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
</AntdSelect>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
mapProps(
|
mapProps(
|
||||||
{
|
{
|
||||||
@ -54,9 +66,8 @@ export const Select: ComposedSelect = connect(
|
|||||||
mapReadPretty((props) => {
|
mapReadPretty((props) => {
|
||||||
const field = useField<any>();
|
const field = useField<any>();
|
||||||
const dataSource = field.dataSource || [];
|
const dataSource = field.dataSource || [];
|
||||||
console.log('field.value', field.value, dataSource)
|
console.log('field.value', field.value, dataSource);
|
||||||
const value = Array.isArray(field.value) ? field.value : [field.value];
|
const values = toArr(field.value);
|
||||||
const values = uniq(value);
|
|
||||||
const findOptions = (options: any[]) => {
|
const findOptions = (options: any[]) => {
|
||||||
let current = [];
|
let current = [];
|
||||||
for (const option of options) {
|
for (const option of options) {
|
||||||
@ -64,100 +75,96 @@ export const Select: ComposedSelect = connect(
|
|||||||
current.push(option);
|
current.push(option);
|
||||||
}
|
}
|
||||||
if (option.children) {
|
if (option.children) {
|
||||||
current = current.concat(findOptions(option.children));
|
const children = findOptions(option.children);
|
||||||
|
current.push(...children);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return current;
|
return current;
|
||||||
}
|
};
|
||||||
const options = findOptions(dataSource);
|
const options = findOptions(dataSource);
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{options
|
{options.map((option, key) => (
|
||||||
.map((option, key) => (
|
<Tag key={key} color={option.color}>
|
||||||
<Tag key={key} color={option.color}>{option.label}</Tag>
|
{option.label}
|
||||||
))}
|
</Tag>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
function getFieldName(field: any) {
|
|
||||||
if (typeof field === 'string') {
|
|
||||||
return field;
|
|
||||||
}
|
|
||||||
if (typeof field === 'object') {
|
|
||||||
return field.name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Select.Object = connect(
|
Select.Object = connect(
|
||||||
(props) => {
|
(props) => {
|
||||||
const field = useField();
|
const field = useField();
|
||||||
const {
|
const {
|
||||||
value,
|
value,
|
||||||
onChange,
|
onChange,
|
||||||
dataRequest,
|
fieldNames = {
|
||||||
labelField: lf,
|
label: 'label',
|
||||||
valueField: vf,
|
value: 'value',
|
||||||
|
},
|
||||||
...others
|
...others
|
||||||
} = props;
|
} = props;
|
||||||
const options = field?.['dataSource'] || props.options || [];
|
const options = field?.['dataSource'] || props.options || [];
|
||||||
console.log({options});
|
let optionValue = undefined;
|
||||||
const labelField = getFieldName(lf);
|
if (isArr(value)) {
|
||||||
const valueField = getFieldName(vf);
|
optionValue = value.map((val) => {
|
||||||
const { data = options, loading } = useRequest(() => dataRequest ? dataRequest : Promise.resolve(options), {
|
|
||||||
refreshDeps: [options]
|
|
||||||
});
|
|
||||||
const getValues = () => {
|
|
||||||
if (!isValid(value)) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
return isArr(value) ? value : [value];
|
|
||||||
}
|
|
||||||
const getOptionValue = () => {
|
|
||||||
const values = getValues().map((item) => {
|
|
||||||
return {
|
return {
|
||||||
value: item[valueField],
|
label: val[fieldNames.label],
|
||||||
label: item[labelField],
|
value: val[fieldNames.value],
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
if (props.mode === 'multiple' || props.mode === 'tags') {
|
} else if (value) {
|
||||||
return values;
|
optionValue = {
|
||||||
}
|
label: value[fieldNames.label],
|
||||||
return values.length ? values[0] : null;
|
value: value[fieldNames.value],
|
||||||
};
|
};
|
||||||
const getOptions = () => {
|
|
||||||
return data.map(item => {
|
|
||||||
return {
|
|
||||||
value: item[valueField],
|
|
||||||
label: item[labelField],
|
|
||||||
};
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<AntdSelect
|
<AntdSelect
|
||||||
|
allowClear
|
||||||
|
labelInValue
|
||||||
{...others}
|
{...others}
|
||||||
loading={loading}
|
value={optionValue}
|
||||||
onChange={(option: any) => {
|
onChange={(selectValue: any) => {
|
||||||
if (!isValid(option)) {
|
if (!selectValue) {
|
||||||
onChange(null);
|
onChange(null);
|
||||||
}
|
}
|
||||||
if (isArr(option)) {
|
if (isArr(selectValue)) {
|
||||||
const optionValues = option.map(item => item.value);
|
const selectValues = selectValue.map((s) => s.value);
|
||||||
const selectValue = data.filter(
|
const values = {};
|
||||||
(item) => optionValues.includes(item[valueField]),
|
if (isArr(value)) {
|
||||||
);
|
value.forEach((option) => {
|
||||||
onChange(selectValue);
|
const val = option[fieldNames.value];
|
||||||
|
if (selectValues.includes(val)) {
|
||||||
|
values[val] = option;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
options.forEach((option) => {
|
||||||
|
const val = option[fieldNames.value];
|
||||||
|
if (selectValues.includes(val)) {
|
||||||
|
values[val] = option;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
console.log({ selectValue, values });
|
||||||
|
onChange(Object.values(values));
|
||||||
} else {
|
} else {
|
||||||
const selectValue = data.find(
|
// 这里不能用 undefined,需要用 null
|
||||||
(item) => item[valueField] === option.value,
|
onChange(
|
||||||
|
options.find(
|
||||||
|
(option) => option[fieldNames.value] === selectValue.value,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
onChange(selectValue);
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
labelInValue
|
options={options.map((option) => {
|
||||||
value={getOptionValue()}
|
return {
|
||||||
options={getOptions()}
|
label: option[fieldNames.label],
|
||||||
|
value: option[fieldNames.value],
|
||||||
|
};
|
||||||
|
})}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -179,7 +186,217 @@ Select.Object = connect(
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
mapReadPretty(Display.ObjectSelect),
|
mapReadPretty(
|
||||||
|
observer((props: any) => {
|
||||||
|
const { value, fieldNames = { label: 'label' }, ...others } = props;
|
||||||
|
if (!value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const values = toArr(value);
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{values.map((val) =>
|
||||||
|
fieldNames.color ? (
|
||||||
|
<Tag color={val[fieldNames.color]}>{val[fieldNames.label]}</Tag>
|
||||||
|
) : (
|
||||||
|
<Tag>{val[fieldNames.label]}</Tag>
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const OptionTagContext = createContext(null);
|
||||||
|
|
||||||
|
const SelectContext = createContext<any>({});
|
||||||
|
|
||||||
|
Select.Drawer = connect(
|
||||||
|
(props) => {
|
||||||
|
const field = useField();
|
||||||
|
const {
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
fieldNames = {
|
||||||
|
label: 'label',
|
||||||
|
value: 'value',
|
||||||
|
},
|
||||||
|
...others
|
||||||
|
} = props;
|
||||||
|
const [visible, setVisible] = useState(false);
|
||||||
|
const schema = useFieldSchema();
|
||||||
|
const options = field?.['dataSource'] || props.options || [];
|
||||||
|
|
||||||
|
let optionValue = undefined;
|
||||||
|
if (isArr(value)) {
|
||||||
|
optionValue = value.map((val) => {
|
||||||
|
return {
|
||||||
|
label: val[fieldNames.label],
|
||||||
|
value: val[fieldNames.value],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
} else if (value) {
|
||||||
|
optionValue = {
|
||||||
|
label: value[fieldNames.label],
|
||||||
|
value: value[fieldNames.value],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const onFieldChange = (selectValue) => {
|
||||||
|
if (!isValid(selectValue)) {
|
||||||
|
onChange(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isArr(selectValue)) {
|
||||||
|
const values = {};
|
||||||
|
if (isArr(value)) {
|
||||||
|
value.forEach((option) => {
|
||||||
|
const val = option[fieldNames.value];
|
||||||
|
if (selectValue.includes(val)) {
|
||||||
|
values[val] = option;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
options.forEach((option) => {
|
||||||
|
const val = option[fieldNames.value];
|
||||||
|
if (selectValue.includes(val)) {
|
||||||
|
values[val] = option;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
onChange(Object.values(values));
|
||||||
|
} else {
|
||||||
|
// 这里不能用 undefined,需要用 null
|
||||||
|
onChange(
|
||||||
|
options.find((option) => option[fieldNames.value] === selectValue),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<AntdSelect
|
||||||
|
{...others}
|
||||||
|
labelInValue
|
||||||
|
open={false}
|
||||||
|
value={optionValue}
|
||||||
|
onClick={() => {
|
||||||
|
setVisible(true);
|
||||||
|
}}
|
||||||
|
onChange={(selectValue: any) => {
|
||||||
|
if (!selectValue) {
|
||||||
|
onChange(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isArr(selectValue)) {
|
||||||
|
const selectValues = selectValue.map((s) => s.value);
|
||||||
|
onFieldChange(selectValues);
|
||||||
|
} else {
|
||||||
|
onFieldChange(selectValue.value);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
></AntdSelect>
|
||||||
|
<Drawer
|
||||||
|
width={'50%'}
|
||||||
|
visible={visible}
|
||||||
|
onClose={() => setVisible(false)}
|
||||||
|
>
|
||||||
|
<SelectContext.Provider
|
||||||
|
value={{
|
||||||
|
onChange(selectValue) {
|
||||||
|
onFieldChange(selectValue);
|
||||||
|
setVisible(false);
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<RecursionField
|
||||||
|
onlyRenderProperties
|
||||||
|
schema={schema}
|
||||||
|
filterProperties={(s) => {
|
||||||
|
return s['x-component'] === 'Select.Options';
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</SelectContext.Provider>
|
||||||
|
</Drawer>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
mapProps(
|
||||||
|
{
|
||||||
|
dataSource: 'options',
|
||||||
|
loading: true,
|
||||||
|
},
|
||||||
|
(props, field) => {
|
||||||
|
return {
|
||||||
|
...props,
|
||||||
|
options: field?.['dataSource'],
|
||||||
|
suffixIcon:
|
||||||
|
field?.['loading'] || field?.['validating'] ? (
|
||||||
|
<LoadingOutlined />
|
||||||
|
) : (
|
||||||
|
props.suffixIcon
|
||||||
|
),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
),
|
||||||
|
mapReadPretty(
|
||||||
|
observer((props: any) => {
|
||||||
|
const field = useField<Formily.Core.Models.Field>();
|
||||||
|
const { fieldNames = { label: 'label' }, ...others } = props;
|
||||||
|
const value = field.value || field.initialValue;
|
||||||
|
const schema = useFieldSchema();
|
||||||
|
console.log({ field, value });
|
||||||
|
if (!value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const values = toArr(value);
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{values.map((data, index) => {
|
||||||
|
return (
|
||||||
|
<OptionTagContext.Provider value={{ index, data, fieldNames }}>
|
||||||
|
<RecursionField
|
||||||
|
schema={schema}
|
||||||
|
onlyRenderProperties
|
||||||
|
filterProperties={(s) => {
|
||||||
|
return s['x-component'] === 'Select.OptionTag';
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</OptionTagContext.Provider>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
Select.Options = observer((props) => {
|
||||||
|
return <>{props.children}</>;
|
||||||
|
});
|
||||||
|
|
||||||
|
export function useSelect() {
|
||||||
|
const { onChange } = useContext(SelectContext);
|
||||||
|
const { data, selectedRowKeys } = useTableContext();
|
||||||
|
return {
|
||||||
|
async run() {
|
||||||
|
console.log({ data, selectedRowKeys });
|
||||||
|
onChange && onChange(selectedRowKeys);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Select.OptionTag = observer((props) => {
|
||||||
|
const [visible, setVisible] = useState(false);
|
||||||
|
const { data, fieldNames } = useContext(OptionTagContext);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Tag onClick={() => setVisible(true)}>{data[fieldNames.label]}</Tag>
|
||||||
|
<Drawer width={'50%'} visible={visible} onClose={() => setVisible(false)}>
|
||||||
|
{props.children}
|
||||||
|
</Drawer>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
export default Select;
|
export default Select;
|
||||||
|
Loading…
Reference in New Issue
Block a user