fix: 修复表单快速添加和弹窗添加功能 (#1141)

Reviewed-on: daoyoucloud/tachybase#1141
Reviewed-by: sealday <zhanglin@daoyoucloud.com>
Co-authored-by: wjh <wwwjh0710@163.com>
Co-committed-by: wjh <wwwjh0710@163.com>
This commit is contained in:
wjh 2024-06-07 16:12:49 +08:00 committed by sealday
parent c2c0ec7724
commit 9d98941267
6 changed files with 207 additions and 215 deletions

View File

@ -6,7 +6,6 @@ import { Space } from 'antd-mobile';
import { ApprovalReachDataType } from '../../component/ApprovalReachDataType'; import { ApprovalReachDataType } from '../../component/ApprovalReachDataType';
import { ApprovalTemplateType } from '../../component/ApprovalTemplateType'; import { ApprovalTemplateType } from '../../component/ApprovalTemplateType';
import { PendingStatus } from '../../constants';
import { useTodosContext } from '../provider/todosContext'; import { useTodosContext } from '../provider/todosContext';
import { TabApplicantType } from './TabApplicantType'; import { TabApplicantType } from './TabApplicantType';
import { TabApprovalItem } from './TabApprovalItem'; import { TabApprovalItem } from './TabApprovalItem';

View File

@ -1,7 +0,0 @@
import { createContext, useContext } from 'react';
export const AntdPopupContext = createContext({});
export const useAntdPopupContext = () => {
return useContext(AntdPopupContext);
};

View File

@ -1,25 +1,27 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { observer, RecursionField, useField, useFieldSchema, useForm } from '@tachybase/schema'; import { observer, RecursionField, Schema, useField, useFieldSchema, useForm } from '@tachybase/schema';
import { Button, CheckList, Divider, Modal, PickerView, Popup, SearchBar, Space, Tag, Toast } from 'antd-mobile'; import { Button, CheckList, Divider, Modal, PickerView, Popup, SearchBar, Space, Tag, Toast } from 'antd-mobile';
import { MInput } from '../Input';
import './style'; import './style';
import { import {
BlockItem, BlockItem,
CollectionProvider_deprecated, CollectionProvider,
SchemaComponent,
useAPIClient, useAPIClient,
useCollection,
useCollectionField,
useCollectionManager, useCollectionManager,
useDesignable, useDesignable,
useRequest, useRequest,
} from '@tachybase/client'; } from '@tachybase/client';
import { isArray } from '@tachybase/utils/client'; import { isArray } from '@tachybase/utils/client';
import { getMobileColor } from '../../../CustomColor';
import { MobileProvider } from '../../../provider';
import { MInput } from '../Input';
import { CreateRecordAction } from './CreateRecordAction'; import { CreateRecordAction } from './CreateRecordAction';
import { useInsertSchema } from './hook/hooks';
import schema from './schema';
import { useStyles } from './style'; import { useStyles } from './style';
export const AntdSelect = observer((props) => { export const AntdSelect = observer((props) => {
@ -30,13 +32,21 @@ export const AntdSelect = observer((props) => {
const [options, setOptions] = useState([]); const [options, setOptions] = useState([]);
const fieldSchema = useFieldSchema(); const fieldSchema = useFieldSchema();
const cm = useCollectionManager(); const cm = useCollectionManager();
const [visibleValue, setVisibleValue] = useState({}); const collection = useCollection();
const [filter, setFilter] = useState(service?.params?.filter); const [filter, setFilter] = useState(service?.params?.filter);
const api = useAPIClient(); const api = useAPIClient();
const field = useField();
const { insertAfterBegin } = useDesignable();
const insertAddNewer = useInsertSchema('AddNewer', fieldSchema, insertAfterBegin);
const [selectValue, setSelectValue] = useState(value); const [selectValue, setSelectValue] = useState(value);
const fieldNamesLabel = fieldNames?.label || 'label';
const fieldNamesValue = fieldNames?.value || 'value';
let inputValue = '';
if (isArray(value)) {
value.forEach((item, index) => {
inputValue += `${item.label}${value.length - 1 === index ? '' : ','}`;
});
} else if (value && typeof value === 'object') {
inputValue = value[fieldNamesLabel];
}
const { data, run } = useRequest( const { data, run } = useRequest(
{ {
resource: collectionName, resource: collectionName,
@ -57,8 +67,8 @@ export const AntdSelect = observer((props) => {
const dataOption = data['data']?.map((value) => { const dataOption = data['data']?.map((value) => {
return { return {
...value, ...value,
label: value[fieldNames.label], label: value[fieldNamesLabel],
value: value[fieldNames.value], value: value[fieldNamesValue],
}; };
}); });
setOptions(dataOption); setOptions(dataOption);
@ -71,13 +81,12 @@ export const AntdSelect = observer((props) => {
} else { } else {
const field = cm.getCollectionField(fieldSchema['x-collection-field']); const field = cm.getCollectionField(fieldSchema['x-collection-field']);
const data = field.uiSchema?.enum; const data = field.uiSchema?.enum;
setVisibleValue(data.find((item) => item.value === value) || '');
setOptions(data); setOptions(data);
} }
}; };
const addData = () => { const addData = (data) => {
api data[fieldNamesLabel] = api
.request({ .request({
url: collectionName + ':create', url: collectionName + ':create',
method: 'post', method: 'post',
@ -96,7 +105,7 @@ export const AntdSelect = observer((props) => {
}); });
} }
const paramsFilter = { ...filter }; const paramsFilter = { ...filter };
delete paramsFilter[fieldNames.label]; delete paramsFilter[fieldNamesLabel];
setFilter(paramsFilter); setFilter(paramsFilter);
setSearchValue(''); setSearchValue('');
setPopupVisible(false); setPopupVisible(false);
@ -107,65 +116,34 @@ export const AntdSelect = observer((props) => {
}; };
const quickAdd = () => { const quickAdd = () => {
const data = {}; const data = {};
data[fieldNames.label] = searchValue; data[fieldNamesLabel] = searchValue;
addData(); addData(data);
};
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 ( return (
<CollectionProvider name={collectionName || collection.name}>
<BlockItem> <BlockItem>
{!value || typeof value === 'object' ? (
<div <div
onClick={() => { onClick={() => {
if (fieldSchema['x-disabled']) return;
setPopupVisible(true); setPopupVisible(true);
checkedPopup(); checkedPopup();
}} }}
style={{ color: '#c5c5c5' }} style={{ color: '#c5c5c5' }}
> >
{isArray(value) && value.length ? ( {value?.length || (value && !isArray(value)) ? (
value.map((item, index) => ( <MInput value={inputValue} disabled={fieldSchema['x-disabled']} />
<Space key={index}>{`${item.label}${value.length - 1 === index ? '' : ','}`}</Space>
))
) : ( ) : (
<Space>{value?.label || '请选择内容'}</Space> <Space>{fieldSchema['x-disabled'] ? '' : '请选择内容'}</Space>
)} )}
</div> </div>
) : (
<Tag color={'default'}>{value?.['label']}</Tag>
)}
<Popup visible={popupVisible} className={`${styles['PopupStyle']}`} closeOnMaskClick> <Popup visible={popupVisible} className={`${styles['PopupStyle']}`} closeOnMaskClick>
<MobileProvider>
<SearchBar <SearchBar
placeholder="请输入内容" placeholder="请输入内容"
value={searchValue} value={searchValue}
onChange={(value) => { onChange={(value) => {
const paramsFilter = { ...filter }; const paramsFilter = { ...filter };
paramsFilter[fieldNames.label] = { $includes: value }; paramsFilter[fieldNamesLabel] = { $includes: value };
setFilter(paramsFilter); setFilter(paramsFilter);
setSearchValue(value); setSearchValue(value);
}} }}
@ -208,11 +186,17 @@ export const AntdSelect = observer((props) => {
)} )}
<Space justify="evenly" align="center"> <Space justify="evenly" align="center">
{/* {addMode === 'modalAdd' ? ( {addMode === 'modalAdd' ? (
<Button color="primary" fill="outline" onClick={modalAdd}> <SchemaComponent
components={{ CreateRecordAction }}
</Button> schema={{
) : null} */} type: 'void',
name: 'CreateRecord',
'x-component': 'CreateRecordAction',
'x-component-props': { fieldSchema },
}}
/>
) : null}
<Button <Button
color="primary" color="primary"
onClick={() => { onClick={() => {
@ -231,7 +215,9 @@ export const AntdSelect = observer((props) => {
</Button> </Button>
</Space> </Space>
</MobileProvider>
</Popup> </Popup>
</BlockItem> </BlockItem>
</CollectionProvider>
); );
}); });

View File

@ -1,29 +1,55 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { import { css, SchemaComponentOptions, useApp, useCollection } from '@tachybase/client';
CollectionProvider, import { observer, RecursionField, useField, useFieldSchema } from '@tachybase/schema';
CollectionProvider_deprecated,
useActionContext,
useCollectionManager,
useCollectionManager_deprecated,
} from '@tachybase/client';
import { RecursionField } from '@tachybase/schema';
import { useInsertSchema } from './hook/hooks'; import { Button, CenterPopup, Modal, Popup } from 'antd-mobile';
import schema from './schema';
export const CreateRecordAction = ({ field, fieldSchema, targetCollection }) => { import { MobileProvider } from '../../../provider';
const [currentCollection, setCurrentCollection] = useState(targetCollection?.name);
const [currentDataSource, setCurrentDataSource] = useState(targetCollection?.dataSource); export const CreateRecordAction = observer(
(props) => {
const { fieldSchema } = props as any;
const [visible, setVisible] = useState(false);
const addNew = fieldSchema.reduceProperties((buf, schema) => {
const found = schema.reduceProperties((buf, schema) => {
if (schema['x-component'] === 'AssociationField.AddNewer') {
return schema;
}
return buf;
});
if (found) {
return found;
}
return buf;
}, {});
const modalAdd = () => {
setVisible(true);
};
return ( return (
<CollectionProvider_deprecated name={currentCollection} dataSource={currentDataSource}> <div>
<RecursionField <Button color="primary" fill="outline" onClick={modalAdd}>
onlyRenderProperties
basePath={field.address} </Button>
schema={fieldSchema}
filterProperties={(s) => { <Popup
return s['x-component'] === 'AssociationField.AddNewer'; visible={visible}
onMaskClick={() => {
setVisible(false);
}} }}
/> className={css`
</CollectionProvider_deprecated> .adm-popup-body {
height: 80vh;
overflow: auto;
}
`}
>
<MobileProvider>
<RecursionField schema={addNew} onlyRenderProperties />
</MobileProvider>
</Popup>
</div>
); );
}; },
{ displayName: 'CreateRecordAction' },
);

View File

@ -15,48 +15,59 @@ export const MSelect = connect(
const fieldSchema = useFieldSchema(); const fieldSchema = useFieldSchema();
const cm = useCollectionManager(); const cm = useCollectionManager();
const collection = cm.getCollection(fieldSchema['x-collection-field']); const collection = cm.getCollection(fieldSchema['x-collection-field']);
const field = useField<any>();
const collectionField = useCollectionField();
const dataSource = field.dataSource || collectionField?.uiSchema.enum || [];
if (collection) { if (collection) {
filterProps['collectionName'] = collection.name; filterProps['collectionName'] = collection.name;
} }
if (typeof filterProps['value'] !== 'object') {
filterProps['value'] = dataSource.filter((item) => item.value.toString() === filterProps['value']);
}
return { ...filterProps }; return { ...filterProps };
}), }),
mapReadPretty((props) => { mapReadPretty((props) => {
const { value, fieldNames } = 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 collectionField = useCollectionField();
const isSlectField = ['multipleSelect', 'select'].includes(collectionField.interface);
const field = useField<any>();
const dataSource = field.dataSource || collectionField?.uiSchema.enum || []; const dataSource = field.dataSource || collectionField?.uiSchema.enum || [];
const options = const fieldNamesLabel = fieldNames?.label || 'label';
typeof value === 'object' if (isSlectField) {
? value const option = [];
.map((item) => { if (!isArray(value)) {
if (dataSource.find((dataItem) => dataItem.value === item.value)) { if (typeof value === 'object') {
return item; option.push(value);
} else {
option.push(dataSource.find((item) => item.value === value));
}
} else {
option.push(...value);
} }
})
.filter(Boolean)
: dataSource.filter((item) => item.value.toString() === value);
return ( return (
<div> <div>
{options.map((option, key) => ( {option.map((item, index) => (
<Tag key={key} color={getMobileColor(option.color)} style={{ margin: '5px' }}> <Tag key={index} color={getMobileColor(item.color)}>
{option.label} {item.label}
</Tag> </Tag>
))} ))}
</div> </div>
); );
} else {
let redValue = '';
if (isArray(value)) {
redValue = value.reduce((prev, curr) => {
return prev + curr[fieldNamesLabel];
}, '');
} else {
redValue = value[fieldNamesLabel];
}
return (
<div>
<Space>{redValue}</Space>
</div>
);
} }
}), }),
); );

View File

@ -1,23 +0,0 @@
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;
};