feat: 添加移动端选择框组件 (#1093)
Reviewed-on: daoyoucloud/tachybase#1093 Reviewed-by: sealday <zhanglin@daoyoucloud.com> Co-authored-by: wangjiahui <wwwjh0710@163.com> Co-committed-by: wangjiahui <wwwjh0710@163.com>
This commit is contained in:
parent
ab49b68213
commit
bc0f05ded2
@ -1,12 +1,14 @@
|
|||||||
import { Field } from '@tachybase/schema';
|
|
||||||
import { useField, useFieldSchema } from '@tachybase/schema';
|
|
||||||
import _ from 'lodash';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { Field, useField, useFieldSchema } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import _ from 'lodash';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { SchemaSettings } from '../../../../application/schema-settings/SchemaSettings';
|
import { SchemaSettings } from '../../../../application/schema-settings/SchemaSettings';
|
||||||
import { useFormBlockContext } from '../../../../block-provider';
|
import { useFormBlockContext } from '../../../../block-provider';
|
||||||
import { useCollectionManager_deprecated, useCollection_deprecated } from '../../../../collection-manager';
|
import { useCollection_deprecated, useCollectionManager_deprecated } from '../../../../collection-manager';
|
||||||
import { useFieldComponentName } from '../../../../common/useFieldComponentName';
|
import { useFieldComponentName } from '../../../../common/useFieldComponentName';
|
||||||
|
import { useCollectionField } from '../../../../data-source';
|
||||||
import { useRecord } from '../../../../record-provider';
|
import { useRecord } from '../../../../record-provider';
|
||||||
import { removeNullCondition, useDesignable, useFieldModeOptions, useIsAddNewForm } from '../../../../schema-component';
|
import { removeNullCondition, useDesignable, useFieldModeOptions, useIsAddNewForm } from '../../../../schema-component';
|
||||||
import { isSubMode } from '../../../../schema-component/antd/association-field/util';
|
import { isSubMode } from '../../../../schema-component/antd/association-field/util';
|
||||||
@ -18,12 +20,11 @@ import {
|
|||||||
useTitleFieldOptions,
|
useTitleFieldOptions,
|
||||||
} from '../../../../schema-component/antd/form-item/FormItem.Settings';
|
} from '../../../../schema-component/antd/form-item/FormItem.Settings';
|
||||||
import { useColumnSchema } from '../../../../schema-component/antd/table-v2/Table.Column.Decorator';
|
import { useColumnSchema } from '../../../../schema-component/antd/table-v2/Table.Column.Decorator';
|
||||||
import { VariableInput, getShouldChange } from '../../../../schema-settings';
|
import { getShouldChange, VariableInput } from '../../../../schema-settings';
|
||||||
|
import { useIsShowMultipleSwitch } from '../../../../schema-settings/hooks/useIsShowMultipleSwitch';
|
||||||
import { SchemaSettingsDataScope } from '../../../../schema-settings/SchemaSettingsDataScope';
|
import { SchemaSettingsDataScope } from '../../../../schema-settings/SchemaSettingsDataScope';
|
||||||
import { SchemaSettingsSortingRule } from '../../../../schema-settings/SchemaSettingsSortingRule';
|
import { SchemaSettingsSortingRule } from '../../../../schema-settings/SchemaSettingsSortingRule';
|
||||||
import { useIsShowMultipleSwitch } from '../../../../schema-settings/hooks/useIsShowMultipleSwitch';
|
|
||||||
import { useLocalVariables, useVariables } from '../../../../variables';
|
import { useLocalVariables, useVariables } from '../../../../variables';
|
||||||
import { useCollectionField } from '../../../../data-source';
|
|
||||||
|
|
||||||
const enableLink = {
|
const enableLink = {
|
||||||
name: 'enableLink',
|
name: 'enableLink',
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { RecursionField, observer, useField, useFieldSchema } from '@tachybase/schema';
|
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
import { observer, RecursionField, useField, useFieldSchema } from '@tachybase/schema';
|
||||||
|
|
||||||
import { CollectionProvider_deprecated, useCollectionManager_deprecated } from '../../../../collection-manager';
|
import { CollectionProvider_deprecated, useCollectionManager_deprecated } from '../../../../collection-manager';
|
||||||
import { CreateAction } from '../../../../schema-initializer/components';
|
import { CreateAction } from '../../../../schema-initializer/components';
|
||||||
import { ActionContextProvider, useActionContext } from '../../action';
|
import { ActionContextProvider, useActionContext } from '../../action';
|
||||||
|
@ -19,6 +19,7 @@ import {
|
|||||||
MMenuBlockInitializer,
|
MMenuBlockInitializer,
|
||||||
MPage,
|
MPage,
|
||||||
MRadio,
|
MRadio,
|
||||||
|
MSelect,
|
||||||
MSettings,
|
MSettings,
|
||||||
MSettingsBlockInitializer,
|
MSettingsBlockInitializer,
|
||||||
MTabBar,
|
MTabBar,
|
||||||
@ -87,6 +88,7 @@ export const MobileCore: React.FC<PropsWithChildren> = (props) => {
|
|||||||
MRadio,
|
MRadio,
|
||||||
MImageUploader,
|
MImageUploader,
|
||||||
CollectionField: CollectionField,
|
CollectionField: CollectionField,
|
||||||
|
MSelect,
|
||||||
}}
|
}}
|
||||||
scope={{
|
scope={{
|
||||||
useGridCardBlockItemProps,
|
useGridCardBlockItemProps,
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
const custonComponent = {
|
const customComponent = {
|
||||||
Input: 'MInput',
|
Input: 'MInput',
|
||||||
'Input.TextArea': 'MInput.TextArea',
|
'Input.TextArea': 'MInput.TextArea',
|
||||||
'Radio.Group': 'MRadio.Group',
|
'Radio.Group': 'MRadio.Group',
|
||||||
'Checkbox.Group': 'MCheckbox.Group',
|
'Checkbox.Group': 'MCheckbox.Group',
|
||||||
'Upload.Attachment': 'MImageUploader',
|
'Upload.Attachment': 'MImageUploader',
|
||||||
DatePicker: 'MDatePicker',
|
DatePicker: 'MDatePicker',
|
||||||
|
Select: 'MSelect',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const canMobileField = (componentName: string) => custonComponent[componentName];
|
export const canMobileField = (componentName: string) => customComponent[componentName];
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import { useCollectionField } from '@tachybase/client';
|
import { css, useCollectionField } from '@tachybase/client';
|
||||||
import { connect, isValid, mapProps, mapReadPretty, useField } from '@tachybase/schema';
|
import { connect, isValid, mapProps, mapReadPretty, useField } from '@tachybase/schema';
|
||||||
|
|
||||||
import { Checkbox, CheckboxGroupProps, CheckboxProps, Tag } from 'antd-mobile';
|
import { Checkbox, CheckboxGroupProps, CheckboxProps, Tag } from 'antd-mobile';
|
||||||
@ -27,7 +27,7 @@ MCheckbox.Group = connect(
|
|||||||
<Checkbox
|
<Checkbox
|
||||||
value={item.value}
|
value={item.value}
|
||||||
key={index}
|
key={index}
|
||||||
style={{ marginRight: '10px' }}
|
style={{ '--icon-size': '12px', '--font-size': '12px' }}
|
||||||
onChange={(status) => {
|
onChange={(status) => {
|
||||||
if (status) {
|
if (status) {
|
||||||
check.push(item.value);
|
check.push(item.value);
|
||||||
@ -37,6 +37,7 @@ MCheckbox.Group = connect(
|
|||||||
}
|
}
|
||||||
props.onChange(check);
|
props.onChange(check);
|
||||||
}}
|
}}
|
||||||
|
{...props}
|
||||||
>
|
>
|
||||||
{item.label}
|
{item.label}
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
|
@ -36,8 +36,8 @@ export const MDatePicker = connect(
|
|||||||
}),
|
}),
|
||||||
mapReadPretty((props) => {
|
mapReadPretty((props) => {
|
||||||
const changeProps = { ...props };
|
const changeProps = { ...props };
|
||||||
changeProps.value = dayjs(props.value).format(props.dateFormat);
|
changeProps.value = props.value ? dayjs(props.value).format('YYYY-MM-DD') : '';
|
||||||
return <Input {...changeProps} readOnly />;
|
return <div>{changeProps.value}</div>;
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
export default MDatePicker;
|
export default MDatePicker;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { css } from '@tachybase/client';
|
||||||
import { connect, mapProps, mapReadPretty } from '@tachybase/schema';
|
import { connect, mapProps, mapReadPretty } from '@tachybase/schema';
|
||||||
|
|
||||||
import { Input, InputProps, TextArea, TextAreaProps } from 'antd-mobile';
|
import { Input, InputProps, TextArea, TextAreaProps } from 'antd-mobile';
|
||||||
@ -10,20 +11,40 @@ type ComposedInput = React.FC<InputProps> & {
|
|||||||
export const MInput: ComposedInput = connect(
|
export const MInput: ComposedInput = connect(
|
||||||
Input,
|
Input,
|
||||||
mapProps((props) => {
|
mapProps((props) => {
|
||||||
return { placeholder: '请输入内容', clearable: true, ...props, style: { fontSize: '12px' } };
|
return { placeholder: '请输入内容', clearable: true, ...props, style: { '--font-size': '12px' } };
|
||||||
}),
|
}),
|
||||||
mapReadPretty((props) => {
|
mapReadPretty((props) => {
|
||||||
return <Input {...props} readOnly style={{ fontSize: '12px' }} />;
|
return (
|
||||||
|
<Input
|
||||||
|
{...props}
|
||||||
|
readOnly
|
||||||
|
className={css`
|
||||||
|
.adm-text-area-element {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
const MTextArea = connect(
|
const MTextArea = connect(
|
||||||
TextArea,
|
TextArea,
|
||||||
mapProps((props) => {
|
mapProps((props) => {
|
||||||
return { ...props, placeholder: '请输入内容', clearable: true, style: { fontSize: '12px' } };
|
return { ...props, placeholder: '请输入内容', clearable: true, style: { '--font-size': '12px' } };
|
||||||
}),
|
}),
|
||||||
mapReadPretty((props) => {
|
mapReadPretty((props) => {
|
||||||
return <TextArea {...props} readOnly style={{ fontSize: '12px' }} />;
|
return (
|
||||||
|
<TextArea
|
||||||
|
{...props}
|
||||||
|
readOnly
|
||||||
|
className={css`
|
||||||
|
.adm-text-area-element {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -26,7 +26,11 @@ MRadio.Group = connect(
|
|||||||
<Radio.Group {...props}>
|
<Radio.Group {...props}>
|
||||||
{dataSource.map((item, index) => {
|
{dataSource.map((item, index) => {
|
||||||
return (
|
return (
|
||||||
<Radio value={item.value} key={index} style={{ marginRight: '10px' }}>
|
<Radio
|
||||||
|
value={item.value}
|
||||||
|
key={index}
|
||||||
|
style={{ '--font-size': '12px', '--icon-size': '18px', marginLeft: '10px' }}
|
||||||
|
>
|
||||||
{item.label}
|
{item.label}
|
||||||
</Radio>
|
</Radio>
|
||||||
);
|
);
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
import { createContext, useContext } from 'react';
|
||||||
|
|
||||||
|
export const AntdPopupContext = createContext({});
|
||||||
|
|
||||||
|
export const useAntdPopupContext = () => {
|
||||||
|
return useContext(AntdPopupContext);
|
||||||
|
};
|
@ -0,0 +1,237 @@
|
|||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { observer, RecursionField, useField, useFieldSchema, useForm } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { Button, CheckList, Divider, Modal, PickerView, Popup, SearchBar, Space, Tag, Toast } from 'antd-mobile';
|
||||||
|
|
||||||
|
import { MInput } from '../Input';
|
||||||
|
|
||||||
|
import './style';
|
||||||
|
|
||||||
|
import {
|
||||||
|
BlockItem,
|
||||||
|
CollectionProvider_deprecated,
|
||||||
|
useAPIClient,
|
||||||
|
useCollectionManager,
|
||||||
|
useDesignable,
|
||||||
|
useRequest,
|
||||||
|
} from '@tachybase/client';
|
||||||
|
import { isArray } from '@tachybase/utils/client';
|
||||||
|
|
||||||
|
import { CreateRecordAction } from './CreateRecordAction';
|
||||||
|
import { useInsertSchema } from './hook/hooks';
|
||||||
|
import schema from './schema';
|
||||||
|
import { useStyles } from './style';
|
||||||
|
|
||||||
|
export const AntdSelect = observer((props) => {
|
||||||
|
const { value, collectionName, service, fieldNames, addMode, onChange, multiple } = props as any;
|
||||||
|
const [popupVisible, setPopupVisible] = useState(false);
|
||||||
|
const [searchValue, setSearchValue] = useState('');
|
||||||
|
const { styles } = useStyles();
|
||||||
|
const [options, setOptions] = useState([]);
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const cm = useCollectionManager();
|
||||||
|
const [visibleValue, setVisibleValue] = useState({});
|
||||||
|
const [filter, setFilter] = useState(service?.params?.filter);
|
||||||
|
const api = useAPIClient();
|
||||||
|
const field = useField();
|
||||||
|
const { insertAfterBegin } = useDesignable();
|
||||||
|
const insertAddNewer = useInsertSchema('AddNewer', fieldSchema, insertAfterBegin);
|
||||||
|
const [selectValue, setSelectValue] = useState(value);
|
||||||
|
const { data, run } = useRequest(
|
||||||
|
{
|
||||||
|
resource: collectionName,
|
||||||
|
action: 'list',
|
||||||
|
params: {
|
||||||
|
filter,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
manual: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
useEffect(() => {
|
||||||
|
checkedPopup();
|
||||||
|
}, [filter]);
|
||||||
|
useEffect(() => {
|
||||||
|
if (data) {
|
||||||
|
const dataOption = data['data']?.map((value) => {
|
||||||
|
return {
|
||||||
|
...value,
|
||||||
|
label: value[fieldNames.label],
|
||||||
|
value: value[fieldNames.value],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
setOptions(dataOption);
|
||||||
|
}
|
||||||
|
}, [data]);
|
||||||
|
|
||||||
|
const checkedPopup = () => {
|
||||||
|
if (collectionName) {
|
||||||
|
run();
|
||||||
|
} else {
|
||||||
|
const field = cm.getCollectionField(fieldSchema['x-collection-field']);
|
||||||
|
const data = field.uiSchema?.enum;
|
||||||
|
setVisibleValue(data.find((item) => item.value === value) || '');
|
||||||
|
setOptions(data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const addData = () => {
|
||||||
|
api
|
||||||
|
.request({
|
||||||
|
url: collectionName + ':create',
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
Toast.show({
|
||||||
|
icon: 'success',
|
||||||
|
content: '添加成功',
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Toast.show({
|
||||||
|
icon: 'fail',
|
||||||
|
content: '失败成功',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const paramsFilter = { ...filter };
|
||||||
|
delete paramsFilter[fieldNames.label];
|
||||||
|
setFilter(paramsFilter);
|
||||||
|
setSearchValue('');
|
||||||
|
setPopupVisible(false);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
console.error;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const quickAdd = () => {
|
||||||
|
const data = {};
|
||||||
|
data[fieldNames.label] = searchValue;
|
||||||
|
addData();
|
||||||
|
};
|
||||||
|
const modalAdd = () => {
|
||||||
|
const collectionField = cm.getCollectionField(fieldSchema['x-collection-field']);
|
||||||
|
// console.log('🚀 ~ modalAdd ~ collectionField:', collectionField);
|
||||||
|
const targetCollection = cm.getCollection(collectionField?.target);
|
||||||
|
|
||||||
|
// insertAddNewer(schema.AddNewer);
|
||||||
|
// const props = {
|
||||||
|
// fieldSchema,
|
||||||
|
// field,
|
||||||
|
// targetCollection,
|
||||||
|
// };
|
||||||
|
Modal.show({
|
||||||
|
content: (
|
||||||
|
<CollectionProvider_deprecated name={targetCollection?.name}>
|
||||||
|
<RecursionField
|
||||||
|
onlyRenderProperties
|
||||||
|
basePath={field.address}
|
||||||
|
schema={fieldSchema}
|
||||||
|
filterProperties={(s) => {
|
||||||
|
return s['x-component'] === 'AssociationField.AddNewer';
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</CollectionProvider_deprecated>
|
||||||
|
),
|
||||||
|
showCloseButton: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<BlockItem>
|
||||||
|
{collectionName ? (
|
||||||
|
<div
|
||||||
|
onClick={() => {
|
||||||
|
setPopupVisible(true);
|
||||||
|
checkedPopup();
|
||||||
|
}}
|
||||||
|
style={{ color: '#c5c5c5' }}
|
||||||
|
>
|
||||||
|
{isArray(value) ? (
|
||||||
|
value.map((item, index) => (
|
||||||
|
<Space key={index}>{`${item.label}${value.length - 1 === index ? '' : ','}`}</Space>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<Space>{value?.label || '请选择内容'}</Space>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<Tag color={'default'}>{value?.['label']}</Tag>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Popup visible={popupVisible} className={`${styles['PopupStyle']}`} closeOnMaskClick>
|
||||||
|
<SearchBar
|
||||||
|
placeholder="请输入内容"
|
||||||
|
value={searchValue}
|
||||||
|
onChange={(value) => {
|
||||||
|
const paramsFilter = { ...filter };
|
||||||
|
paramsFilter[fieldNames.label] = { $includes: value };
|
||||||
|
setFilter(paramsFilter);
|
||||||
|
setSearchValue(value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{searchValue && addMode === 'quickAdd' ? (
|
||||||
|
<Space justify="center" align="center" onClick={quickAdd}>
|
||||||
|
+ 创建{searchValue}
|
||||||
|
</Space>
|
||||||
|
) : null}
|
||||||
|
<Divider />
|
||||||
|
{multiple ? (
|
||||||
|
<CheckList
|
||||||
|
multiple
|
||||||
|
className={`${styles['checkListStyle']}`}
|
||||||
|
onChange={(value) => {
|
||||||
|
if (!value.length) {
|
||||||
|
setSelectValue(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const filterValue = options.filter((item) => value.includes(item.value));
|
||||||
|
setSelectValue(filterValue);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{options.map((item, index) => {
|
||||||
|
return (
|
||||||
|
<CheckList.Item key={index} value={item.value}>
|
||||||
|
{item.label}
|
||||||
|
</CheckList.Item>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</CheckList>
|
||||||
|
) : (
|
||||||
|
<PickerView
|
||||||
|
columns={[options]}
|
||||||
|
onChange={(value) => {
|
||||||
|
const changeValue = options.find((item) => item[fieldNames.value] === value[0]);
|
||||||
|
setSelectValue(changeValue);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Space justify="evenly" align="center">
|
||||||
|
{/* {addMode === 'modalAdd' ? (
|
||||||
|
<Button color="primary" fill="outline" onClick={modalAdd}>
|
||||||
|
添加
|
||||||
|
</Button>
|
||||||
|
) : null} */}
|
||||||
|
<Button
|
||||||
|
color="primary"
|
||||||
|
onClick={() => {
|
||||||
|
setPopupVisible(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
取消
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
color="primary"
|
||||||
|
onClick={() => {
|
||||||
|
onChange(selectValue);
|
||||||
|
setPopupVisible(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
确定
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
</Popup>
|
||||||
|
</BlockItem>
|
||||||
|
);
|
||||||
|
});
|
@ -0,0 +1,7 @@
|
|||||||
|
import { createContext, useContext } from 'react';
|
||||||
|
|
||||||
|
export const AntdSelectContext = createContext({});
|
||||||
|
|
||||||
|
export const useAntdSelectContext = () => {
|
||||||
|
return useContext(AntdSelectContext);
|
||||||
|
};
|
@ -0,0 +1,29 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import {
|
||||||
|
CollectionProvider,
|
||||||
|
CollectionProvider_deprecated,
|
||||||
|
useActionContext,
|
||||||
|
useCollectionManager,
|
||||||
|
useCollectionManager_deprecated,
|
||||||
|
} from '@tachybase/client';
|
||||||
|
import { RecursionField } from '@tachybase/schema';
|
||||||
|
|
||||||
|
import { useInsertSchema } from './hook/hooks';
|
||||||
|
import schema from './schema';
|
||||||
|
|
||||||
|
export const CreateRecordAction = ({ field, fieldSchema, targetCollection }) => {
|
||||||
|
const [currentCollection, setCurrentCollection] = useState(targetCollection?.name);
|
||||||
|
const [currentDataSource, setCurrentDataSource] = useState(targetCollection?.dataSource);
|
||||||
|
return (
|
||||||
|
<CollectionProvider_deprecated name={currentCollection} dataSource={currentDataSource}>
|
||||||
|
<RecursionField
|
||||||
|
onlyRenderProperties
|
||||||
|
basePath={field.address}
|
||||||
|
schema={fieldSchema}
|
||||||
|
filterProperties={(s) => {
|
||||||
|
return s['x-component'] === 'AssociationField.AddNewer';
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</CollectionProvider_deprecated>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,56 @@
|
|||||||
|
import React, { useEffect } from 'react';
|
||||||
|
import { css, useCollectionField, useCollectionManager } from '@tachybase/client';
|
||||||
|
import { connect, isValid, mapProps, mapReadPretty, useField, useFieldSchema } from '@tachybase/schema';
|
||||||
|
import { isArray } from '@tachybase/utils/client';
|
||||||
|
|
||||||
|
import { Input, Space, Tag } from 'antd-mobile';
|
||||||
|
|
||||||
|
import { getMobileColor } from '../../../CustomColor';
|
||||||
|
import { AntdSelect } from './AntdSelect';
|
||||||
|
|
||||||
|
export const MSelect = connect(
|
||||||
|
AntdSelect,
|
||||||
|
mapProps((props) => {
|
||||||
|
const filterProps = { ...props };
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const cm = useCollectionManager();
|
||||||
|
const collection = cm.getCollection(fieldSchema['x-collection-field']);
|
||||||
|
if (collection) {
|
||||||
|
filterProps['collectionName'] = collection.name;
|
||||||
|
}
|
||||||
|
return { ...filterProps };
|
||||||
|
}),
|
||||||
|
mapReadPretty((props) => {
|
||||||
|
const { value, fieldNames } = props;
|
||||||
|
const isCollectionField = typeof value === 'object' && fieldNames;
|
||||||
|
if (isCollectionField) {
|
||||||
|
const isArrayField = isArray(value);
|
||||||
|
return isArrayField ? (
|
||||||
|
<div>
|
||||||
|
{value.map((item, index) => (
|
||||||
|
<Space key={index}>{`${item?.[fieldNames.label] || ''}${value.length - 1 === index ? '' : ','}`}</Space>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<Space>{value?.[fieldNames.label] || ''}</Space>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const field = useField<any>();
|
||||||
|
const collectionField = useCollectionField();
|
||||||
|
const dataSource = field.dataSource || collectionField?.uiSchema.enum || [];
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{dataSource
|
||||||
|
.filter((option) => option.value == value)
|
||||||
|
.map((option, key) => (
|
||||||
|
<Tag key={key} color={getMobileColor(option.color)}>
|
||||||
|
{option.label}
|
||||||
|
</Tag>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
export default MSelect;
|
@ -0,0 +1,23 @@
|
|||||||
|
import { useCallback } from 'react';
|
||||||
|
import { useDesignable } from '@tachybase/client';
|
||||||
|
import { GeneralField, reaction, useField, useFieldSchema } from '@tachybase/schema';
|
||||||
|
import { flatten, getValuesByPath } from '@tachybase/utils/client';
|
||||||
|
|
||||||
|
import _, { isString } from 'lodash';
|
||||||
|
import cloneDeep from 'lodash/cloneDeep';
|
||||||
|
|
||||||
|
export const useInsertSchema = (component, fieldSchema, insertAfterBegin) => {
|
||||||
|
const insert = (ss) => {
|
||||||
|
const schema = fieldSchema.reduceProperties((buf, s) => {
|
||||||
|
if (s['x-component'] === 'AssociationField.' + component) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}, null);
|
||||||
|
if (!schema) {
|
||||||
|
insertAfterBegin(cloneDeep(ss));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return insert;
|
||||||
|
};
|
@ -0,0 +1 @@
|
|||||||
|
export * from './Select';
|
@ -0,0 +1,131 @@
|
|||||||
|
export default {
|
||||||
|
Nester: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'AssociationField.Nester',
|
||||||
|
properties: {
|
||||||
|
grid: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid',
|
||||||
|
'x-initializer': 'form:configureFields',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
AddNewer: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'AssociationField.AddNewer',
|
||||||
|
'x-action': 'create',
|
||||||
|
title: '{{ t("Add record") }}',
|
||||||
|
'x-component-props': {
|
||||||
|
className: 'nb-action-popup',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
tabs: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Tabs',
|
||||||
|
'x-component-props': {},
|
||||||
|
'x-initializer': 'TabPaneInitializersForCreateFormBlock',
|
||||||
|
properties: {
|
||||||
|
tab1: {
|
||||||
|
type: 'void',
|
||||||
|
title: '{{t("Add new")}}',
|
||||||
|
'x-component': 'Tabs.TabPane',
|
||||||
|
'x-designer': 'Tabs.Designer',
|
||||||
|
'x-component-props': {},
|
||||||
|
properties: {
|
||||||
|
grid: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid',
|
||||||
|
'x-initializer': 'popup:addNew:addBlock',
|
||||||
|
properties: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Selector: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'AssociationField.Selector',
|
||||||
|
title: '{{ t("Select record") }}',
|
||||||
|
'x-component-props': {
|
||||||
|
className: 'nb-record-picker-selector',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
grid: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid',
|
||||||
|
'x-initializer': 'popup:tableSelector:addBlock',
|
||||||
|
properties: {},
|
||||||
|
},
|
||||||
|
footer: {
|
||||||
|
'x-component': 'Action.Container.Footer',
|
||||||
|
'x-component-props': {},
|
||||||
|
properties: {
|
||||||
|
actions: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'ActionBar',
|
||||||
|
'x-component-props': {},
|
||||||
|
properties: {
|
||||||
|
submit: {
|
||||||
|
title: '{{ t("Submit") }}',
|
||||||
|
'x-action': 'submit',
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-use-component-props': 'usePickActionProps',
|
||||||
|
// 'x-designer': 'Action.Designer',
|
||||||
|
'x-toolbar': 'ActionSchemaToolbar',
|
||||||
|
'x-settings': 'actionSettings:submit',
|
||||||
|
'x-component-props': {
|
||||||
|
type: 'primary',
|
||||||
|
htmlType: 'submit',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Viewer: {
|
||||||
|
type: 'void',
|
||||||
|
title: '{{ t("View record") }}',
|
||||||
|
'x-component': 'AssociationField.Viewer',
|
||||||
|
'x-component-props': {
|
||||||
|
className: 'nb-action-popup',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
tabs: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Tabs',
|
||||||
|
'x-component-props': {},
|
||||||
|
'x-initializer': 'TabPaneInitializers',
|
||||||
|
properties: {
|
||||||
|
tab1: {
|
||||||
|
type: 'void',
|
||||||
|
title: '{{t("Details")}}',
|
||||||
|
'x-component': 'Tabs.TabPane',
|
||||||
|
'x-designer': 'Tabs.Designer',
|
||||||
|
'x-component-props': {},
|
||||||
|
properties: {
|
||||||
|
grid: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid',
|
||||||
|
'x-initializer': 'popup:common:addBlock',
|
||||||
|
properties: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
SubTable: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'AssociationField.SubTable',
|
||||||
|
'x-initializer': 'table:configureColumns',
|
||||||
|
'x-initializer-props': {
|
||||||
|
action: false,
|
||||||
|
},
|
||||||
|
properties: {},
|
||||||
|
},
|
||||||
|
};
|
@ -0,0 +1,25 @@
|
|||||||
|
import { createStyles } from '@tachybase/client';
|
||||||
|
|
||||||
|
export const useStyles = createStyles(({ css }) => ({
|
||||||
|
PopupStyle: css`
|
||||||
|
.adm-popup-body {
|
||||||
|
padding: 10px;
|
||||||
|
.adm-space {
|
||||||
|
width: 100%;
|
||||||
|
margin: 10px 0 10px 0;
|
||||||
|
color: #4592ff;
|
||||||
|
button {
|
||||||
|
width: 23vw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.adm-divider {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.adm-list-body {
|
||||||
|
height: 30vh;
|
||||||
|
overflow: auto;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
}));
|
@ -3,3 +3,4 @@ export * from './Checkbox';
|
|||||||
export * from './DatePicker';
|
export * from './DatePicker';
|
||||||
export * from './ImageUploader';
|
export * from './ImageUploader';
|
||||||
export * from './Radio';
|
export * from './Radio';
|
||||||
|
export * from './Select';
|
||||||
|
@ -2,6 +2,8 @@ import React, { useEffect, useMemo } from 'react';
|
|||||||
import {
|
import {
|
||||||
CollectionFieldProvider,
|
CollectionFieldProvider,
|
||||||
useCollectionField,
|
useCollectionField,
|
||||||
|
useCollectionManager,
|
||||||
|
useCollectionManager_deprecated,
|
||||||
useCompile,
|
useCompile,
|
||||||
useComponent,
|
useComponent,
|
||||||
useFormBlockContext,
|
useFormBlockContext,
|
||||||
@ -28,11 +30,15 @@ export const CollectionFieldInternalField: React.FC = (props: Props) => {
|
|||||||
const compile = useCompile();
|
const compile = useCompile();
|
||||||
const field = useField<Field>();
|
const field = useField<Field>();
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
|
const { getCollectionJoinField, getCollection } = useCollectionManager_deprecated();
|
||||||
const { uiSchema: uiSchemaOrigin, defaultValue } = useCollectionField();
|
const { uiSchema: uiSchemaOrigin, defaultValue } = useCollectionField();
|
||||||
const { isAllowToSetDefaultValue } = useIsAllowToSetDefaultValue();
|
const { isAllowToSetDefaultValue } = useIsAllowToSetDefaultValue();
|
||||||
const uiSchema = useMemo(() => compile(uiSchemaOrigin), [JSON.stringify(uiSchemaOrigin)]);
|
const uiSchema = useMemo(() => compile(uiSchemaOrigin), [JSON.stringify(uiSchemaOrigin)]);
|
||||||
|
|
||||||
const isMobile = useIsMobile();
|
const isMobile = useIsMobile();
|
||||||
const Component = useComponent(component || uiComponent(isMobile, uiSchema) || 'Input');
|
const currModel = getCurrModel({ getCollectionJoinField, getCollection, fieldSchema, uiSchema });
|
||||||
|
const Component = useComponent(component || uiComponent(isMobile, uiSchema, currModel) || 'Input');
|
||||||
|
|
||||||
const setFieldProps = (key, value) => {
|
const setFieldProps = (key, value) => {
|
||||||
field[key] = typeof field[key] === 'undefined' ? value : field[key];
|
field[key] = typeof field[key] === 'undefined' ? value : field[key];
|
||||||
};
|
};
|
||||||
@ -95,8 +101,8 @@ export const CollectionField = connect((props) => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
export const uiComponent = (isMobile, uiSchema) => {
|
export const uiComponent = (isMobile, uiSchema, currMode?) => {
|
||||||
const isMobileComponent = canMobileField(uiSchema['x-component']);
|
const isMobileComponent = canMobileField(currMode || uiSchema['x-component']);
|
||||||
if (isMobile && isMobileComponent) {
|
if (isMobile && isMobileComponent) {
|
||||||
return isMobileComponent;
|
return isMobileComponent;
|
||||||
} else {
|
} else {
|
||||||
@ -104,4 +110,15 @@ export const uiComponent = (isMobile, uiSchema) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getCurrModel = ({ getCollectionJoinField, getCollection, fieldSchema, uiSchema }) => {
|
||||||
|
const collectionField = getCollectionJoinField(fieldSchema['x-collection-field']);
|
||||||
|
const isFileCollection = getCollection(collectionField?.target)?.template === 'file';
|
||||||
|
const isTreeCollection = getCollection(collectionField?.target)?.template === 'tree';
|
||||||
|
|
||||||
|
const currentMode =
|
||||||
|
fieldSchema['x-component-props']?.mode ||
|
||||||
|
(isFileCollection ? 'FileManager' : isTreeCollection ? 'Cascader' : 'Select');
|
||||||
|
return currentMode && uiSchema['x-component'] === 'AssociationField' ? currentMode : undefined;
|
||||||
|
};
|
||||||
|
|
||||||
CollectionField.displayName = 'CollectionField';
|
CollectionField.displayName = 'CollectionField';
|
||||||
|
Loading…
Reference in New Issue
Block a user