feat: 子表格新增快速添加功能 (#1122)
Co-authored-by: sealday <zhanglin@daoyoucloud.com> Reviewed-on: daoyoucloud/tachybase#1122 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:
parent
d0a4615ef7
commit
019a42b0ed
@ -830,5 +830,6 @@
|
||||
"Designer properties": "Designer properties",
|
||||
"Load": "Load",
|
||||
"Dump": "Dump",
|
||||
"Chang on Parent":"Chang on Parent"
|
||||
"Chang on Parent":"Chang on Parent",
|
||||
"Please enter search content":"Please enter search content"
|
||||
}
|
||||
|
@ -933,5 +933,6 @@
|
||||
"Dump": "存储",
|
||||
"Sorry, the page you visited does not exist.": "对不起,您访问的页面不存在。",
|
||||
"Back Home": "回到主页",
|
||||
"Chang on Parent": "选择父级"
|
||||
"Chang on Parent": "选择父级",
|
||||
"Please enter search content":"请输入查询内容"
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { useCollectionManager } from '@tachybase/client';
|
||||
import { ArrayItems } from '@tachybase/components';
|
||||
import { Field, ISchema, useField, useFieldSchema } from '@tachybase/schema';
|
||||
|
||||
@ -6,7 +7,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import { SchemaSettings } from '../../../../application/schema-settings/SchemaSettings';
|
||||
import { useCollectionManager_deprecated, useSortFields } from '../../../../collection-manager';
|
||||
import { useFieldComponentName } from '../../../../common/useFieldComponentName';
|
||||
import { useDesignable, useFieldModeOptions, useIsAddNewForm } from '../../../../schema-component';
|
||||
import { useCompile, useDesignable, useFieldModeOptions, useIsAddNewForm } from '../../../../schema-component';
|
||||
import { isSubMode } from '../../../../schema-component/antd/association-field/util';
|
||||
import { useIsAssociationField, useIsFieldReadPretty } from '../../../../schema-component/antd/form-item';
|
||||
|
||||
@ -242,7 +243,188 @@ export const allowAddNewData = {
|
||||
},
|
||||
};
|
||||
|
||||
export const isQuickAddTabs = {
|
||||
name: 'isquickaddtabs',
|
||||
type: 'switch',
|
||||
useVisible() {
|
||||
const readPretty = useIsFieldReadPretty();
|
||||
const isAssociationField = useIsAssociationField();
|
||||
return !readPretty && isAssociationField;
|
||||
},
|
||||
|
||||
useComponentProps() {
|
||||
const { t } = useTranslation();
|
||||
const field = useField<Field>();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const { dn, refresh } = useDesignable();
|
||||
return {
|
||||
title: t('Is Quick Add Tabs'),
|
||||
checked: fieldSchema['x-component-props']?.isQuickAdd || false,
|
||||
onChange(value) {
|
||||
const schema = {
|
||||
['x-uid']: fieldSchema['x-uid'],
|
||||
};
|
||||
field.componentProps['isQuickAdd'] = value;
|
||||
fieldSchema['x-component-props'] = fieldSchema['x-component-props'] || {};
|
||||
fieldSchema['x-component-props']['isQuickAdd'] = value;
|
||||
schema['x-component-props'] = fieldSchema['x-component-props'];
|
||||
dn.emit('patch', {
|
||||
schema,
|
||||
});
|
||||
refresh();
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
export const setQuickAddTabs = {
|
||||
name: 'setquickaddtabs',
|
||||
type: 'select',
|
||||
useComponentProps() {
|
||||
const { t } = useTranslation();
|
||||
const field = useField<Field>();
|
||||
const compile = useCompile();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const cm = useCollectionManager();
|
||||
const options = cm.getCollection(fieldSchema['x-collection-field']);
|
||||
const defVal = fieldSchema['x-component-props']['quickAddField'] || 'none';
|
||||
const { dn } = useDesignable();
|
||||
const isAddNewForm = useIsAddNewForm();
|
||||
const fieldTabsOptions = options.fields
|
||||
.map((item) => {
|
||||
if (item.interface === 'm2o' || item.interface === 'select') {
|
||||
return {
|
||||
...item,
|
||||
label: compile(item.uiSchema?.title),
|
||||
value: item.name,
|
||||
};
|
||||
}
|
||||
})
|
||||
.filter(Boolean);
|
||||
fieldTabsOptions.unshift({
|
||||
label: 'none',
|
||||
value: 'none',
|
||||
});
|
||||
return {
|
||||
title: t('Set Quick Add Tabs'),
|
||||
options: fieldTabsOptions,
|
||||
value: defVal,
|
||||
onChange(mode) {
|
||||
const schema = {
|
||||
['x-uid']: fieldSchema['x-uid'],
|
||||
};
|
||||
fieldSchema['x-component-props'] = fieldSchema['x-component-props'] || {};
|
||||
fieldSchema['x-component-props']['quickAddField'] = {
|
||||
fieldInterface: fieldTabsOptions.find((item) => item.value === mode)['interface'] || 'none',
|
||||
value: mode,
|
||||
};
|
||||
schema['x-component-props'] = fieldSchema['x-component-props'];
|
||||
field.componentProps = field.componentProps || {};
|
||||
field.componentProps['quickAddField'] = fieldSchema['x-component-props']['quickAddField'];
|
||||
|
||||
// 子表单状态不允许设置默认值
|
||||
if (isSubMode(fieldSchema) && isAddNewForm) {
|
||||
// @ts-ignore
|
||||
schema.default = null;
|
||||
fieldSchema.default = null;
|
||||
field.setInitialValue(null);
|
||||
field.setValue(null);
|
||||
}
|
||||
|
||||
void dn.emit('patch', {
|
||||
schema,
|
||||
});
|
||||
dn.refresh();
|
||||
},
|
||||
};
|
||||
},
|
||||
useVisible() {
|
||||
const fieldSchema = useFieldSchema();
|
||||
return fieldSchema['x-component-props']['isQuickAdd'];
|
||||
},
|
||||
};
|
||||
|
||||
export const setQuickAddParentTabs = {
|
||||
name: 'setquickaddparenttabs',
|
||||
type: 'select',
|
||||
useComponentProps() {
|
||||
const { t } = useTranslation();
|
||||
const field = useField<Field>();
|
||||
const compile = useCompile();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const cm = useCollectionManager();
|
||||
const { value: quickField } = fieldSchema['x-component-props']?.['quickAddField'] || {};
|
||||
const options = cm.getCollectionFields(`${fieldSchema['x-collection-field']}.${quickField}`);
|
||||
const { dn } = useDesignable();
|
||||
const isAddNewForm = useIsAddNewForm();
|
||||
const fieldTabsOptions = options
|
||||
.map((item) => {
|
||||
if (item.interface === 'm2o')
|
||||
return {
|
||||
...item,
|
||||
label: compile(item.uiSchema.title),
|
||||
value: item.name,
|
||||
};
|
||||
})
|
||||
.filter(Boolean);
|
||||
fieldTabsOptions.unshift({
|
||||
label: t('none'),
|
||||
value: 'none',
|
||||
});
|
||||
const defValue = fieldSchema['x-component-props']?.['quickAddParentCollection']?.value || 'none';
|
||||
return {
|
||||
title: t('Set Quick Add Parent Tabs'),
|
||||
options: fieldTabsOptions,
|
||||
value: defValue,
|
||||
onChange(mode) {
|
||||
const schema = {
|
||||
['x-uid']: fieldSchema['x-uid'],
|
||||
};
|
||||
fieldSchema['x-component-props'] = fieldSchema['x-component-props'] || {};
|
||||
fieldSchema['x-component-props']['quickAddParentCollection'] = {
|
||||
collectionField: `${fieldSchema['x-collection-field']}.${quickField}.${mode}`,
|
||||
value: mode,
|
||||
};
|
||||
schema['x-component-props'] = fieldSchema['x-component-props'];
|
||||
field.componentProps = field.componentProps || {};
|
||||
field.componentProps['quickAddParentCollection'] = {
|
||||
collectionField: `${fieldSchema['x-collection-field']}.${quickField}.${mode}`,
|
||||
value: mode,
|
||||
};
|
||||
// 子表单状态不允许设置默认值
|
||||
if (isSubMode(fieldSchema) && isAddNewForm) {
|
||||
// @ts-ignore
|
||||
schema.default = null;
|
||||
fieldSchema.default = null;
|
||||
field.setInitialValue(null);
|
||||
field.setValue(null);
|
||||
}
|
||||
void dn.emit('patch', {
|
||||
schema,
|
||||
});
|
||||
dn.refresh();
|
||||
},
|
||||
};
|
||||
},
|
||||
useVisible() {
|
||||
const fieldSchema = useFieldSchema();
|
||||
return (
|
||||
fieldSchema['x-component-props']['isQuickAdd'] &&
|
||||
fieldSchema['x-component-props']['quickAddField'] &&
|
||||
fieldSchema['x-component-props']['quickAddField'] !== 'none'
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export const subTablePopoverComponentFieldSettings = new SchemaSettings({
|
||||
name: 'fieldSettings:component:SubTable',
|
||||
items: [fieldComponent, allowAddNewData, allowSelectExistingRecord, setDefaultSortingRules],
|
||||
items: [
|
||||
fieldComponent,
|
||||
allowAddNewData,
|
||||
allowSelectExistingRecord,
|
||||
setDefaultSortingRules,
|
||||
isQuickAddTabs,
|
||||
setQuickAddTabs,
|
||||
setQuickAddParentTabs,
|
||||
],
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useContext, useMemo, useState } from 'react';
|
||||
import React, { useContext, useEffect, useMemo, useState } from 'react';
|
||||
import {
|
||||
action,
|
||||
ArrayField,
|
||||
@ -7,11 +7,13 @@ import {
|
||||
observer,
|
||||
RecursionField,
|
||||
useFieldSchema,
|
||||
useForm,
|
||||
} from '@tachybase/schema';
|
||||
|
||||
import { Button } from 'antd';
|
||||
import { useAsyncEffect } from 'ahooks';
|
||||
import { Button, Tabs } from 'antd';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { unionBy, uniqBy } from 'lodash';
|
||||
import { set, unionBy, uniqBy } from 'lodash';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import {
|
||||
@ -21,11 +23,12 @@ import {
|
||||
SchemaComponentOptions,
|
||||
useActionContext,
|
||||
} from '../..';
|
||||
import { useAPIClient, useRequest } from '../../../api-client';
|
||||
import { useCreateActionProps } from '../../../block-provider/hooks';
|
||||
import { FormActiveFieldsProvider } from '../../../block-provider/hooks/useFormActiveFields';
|
||||
import { TableSelectorParamsProvider } from '../../../block-provider/TableSelectorProvider';
|
||||
import { CollectionProvider_deprecated } from '../../../collection-manager';
|
||||
import { CollectionRecordProvider, useCollectionRecord } from '../../../data-source';
|
||||
import { CollectionRecordProvider, useCollectionManager, useCollectionRecord } from '../../../data-source';
|
||||
import { markRecordAsNew } from '../../../data-source/collection-record/isNewRecord';
|
||||
import { FlagProvider } from '../../../flag-provider';
|
||||
import { useCompile } from '../../hooks';
|
||||
@ -33,6 +36,7 @@ import { ActionContextProvider } from '../action';
|
||||
import { Table } from '../table-v2/Table';
|
||||
import { useAssociationFieldContext, useFieldNames } from './hooks';
|
||||
import { useTableSelectorProps } from './InternalPicker';
|
||||
import { InternalTabs } from './SubTabs/InternamTabs';
|
||||
import { getLabelFormatValue, useLabelUiSchema } from './util';
|
||||
|
||||
const useStyles = createStyles(({ css }) => {
|
||||
@ -106,7 +110,7 @@ export const SubTable: any = observer(
|
||||
const compile = useCompile();
|
||||
const labelUiSchema = useLabelUiSchema(collectionField, fieldNames?.label || 'label');
|
||||
const recordV2 = useCollectionRecord();
|
||||
|
||||
const [fieldValue, setFieldValue] = useState([]);
|
||||
const move = (fromIndex: number, toIndex: number) => {
|
||||
if (toIndex === undefined) return;
|
||||
if (!isArr(field.value)) return;
|
||||
@ -122,6 +126,7 @@ export const SubTable: any = observer(
|
||||
return field.onInput(field.value);
|
||||
});
|
||||
};
|
||||
|
||||
field.move = move;
|
||||
|
||||
const options = useMemo(() => {
|
||||
@ -172,11 +177,17 @@ export const SubTable: any = observer(
|
||||
const filter = list.length ? { $and: [{ [`${targetKey}.$ne`]: list }] } : {};
|
||||
return filter;
|
||||
};
|
||||
const tabsProps = {
|
||||
...props,
|
||||
fieldValue,
|
||||
setFieldValue,
|
||||
};
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<FlagProvider isInSubTable>
|
||||
<CollectionRecordProvider record={null} parentRecord={recordV2}>
|
||||
<FormActiveFieldsProvider name="nester">
|
||||
<InternalTabs {...tabsProps} />
|
||||
<Table
|
||||
className={styles.table}
|
||||
bordered
|
||||
@ -185,6 +196,7 @@ export const SubTable: any = observer(
|
||||
showIndex
|
||||
dragSort={field.editable}
|
||||
showDel={field.editable}
|
||||
setFieldValue={setFieldValue}
|
||||
pagination={!!field.componentProps.pagination}
|
||||
rowSelection={{ type: 'none', hideSelectAll: true }}
|
||||
footer={() =>
|
||||
@ -198,6 +210,7 @@ export const SubTable: any = observer(
|
||||
onClick={() => {
|
||||
field.value = field.value || [];
|
||||
field.value.push(markRecordAsNew({}));
|
||||
setFieldValue([...field.value]);
|
||||
}}
|
||||
>
|
||||
{t('Add new')}
|
||||
|
@ -0,0 +1,265 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { ArrayField, observer, onFieldChange, Schema, useFieldSchema, useFormEffects } from '@tachybase/schema';
|
||||
|
||||
import { CheckOutlined, CheckSquareOutlined, SearchOutlined } from '@ant-design/icons';
|
||||
import { useAsyncEffect, useDeepCompareEffect } from 'ahooks';
|
||||
import { Badge, Button, Input, Space, Tabs } from 'antd';
|
||||
import flat from 'flat';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useAPIClient } from '../../../../api-client';
|
||||
import { useCollectionManager } from '../../../../data-source';
|
||||
import { markRecordAsNew } from '../../../../data-source/collection-record/isNewRecord';
|
||||
import { useAssociationFieldContext } from '../hooks';
|
||||
import { useFieldServiceFilter } from './hook';
|
||||
|
||||
export const InternalTabs = observer((props) => {
|
||||
const { fieldValue, setFieldValue } = props as any;
|
||||
const fieldSchema = useFieldSchema();
|
||||
const cm = useCollectionManager();
|
||||
const api = useAPIClient();
|
||||
const isQuickAdd = fieldSchema['parent']['x-component-props']['isQuickAdd'];
|
||||
const { value: quickAddField, fieldInterface } = fieldSchema['parent']['x-component-props']?.['quickAddField'] || {};
|
||||
const quickAddParentField = fieldSchema['parent']['x-component-props']['quickAddParentCollection'];
|
||||
const [options, setOptions] = useState([]);
|
||||
const [defOptions, setDefOptions] = useState([]);
|
||||
const { field, options: collectionField } = useAssociationFieldContext<ArrayField>();
|
||||
const { t } = useTranslation();
|
||||
const [changeForm, setChangeForm] = useState<any>();
|
||||
|
||||
const tableSchema = fieldSchema.reduceProperties((buf, schema) => {
|
||||
const found = schema.reduceProperties(
|
||||
(buf, schema) => {
|
||||
if (schema.name === quickAddField) {
|
||||
return schema;
|
||||
}
|
||||
return buf;
|
||||
},
|
||||
new Schema({ name: 'not-found' }),
|
||||
);
|
||||
if (found.name === quickAddField) {
|
||||
return found;
|
||||
}
|
||||
return buf;
|
||||
}, new Schema({}));
|
||||
const tabparams = tableSchema['x-component-props']?.['service']?.['params'];
|
||||
const [fieldServiceFilter, setFieldServiceFilter] = useFieldServiceFilter(tabparams?.filter);
|
||||
const formFilter = flat(tabparams?.filter || {});
|
||||
const formFieldFilter = Object.values(formFilter)
|
||||
?.map((item) => {
|
||||
const field = item as String;
|
||||
const match = field.match(/^{{\$nForm\.(.*?)\./);
|
||||
if (match) return match[1];
|
||||
})
|
||||
.filter(Boolean);
|
||||
useAsyncEffect(async () => {
|
||||
const itemParams = {};
|
||||
const optionsItem = [];
|
||||
if (tabparams?.filter && !fieldServiceFilter) return;
|
||||
if ((quickAddField || quickAddField !== 'none' || !isQuickAdd) && fieldSchema.properties) {
|
||||
const params = { pageSize: 99999, filter: JSON.stringify(fieldServiceFilter) };
|
||||
if (quickAddParentField && quickAddParentField?.value !== 'none') {
|
||||
params['appends'] = [quickAddParentField.value];
|
||||
const collection = cm.getCollection(quickAddParentField.collectionField);
|
||||
const parentItem = await api.request({
|
||||
url: collection.name + ':list',
|
||||
params: { pageSize: 9999 },
|
||||
});
|
||||
itemParams['parentTitleField'] = collection.titleField;
|
||||
itemParams['parentOptions'] = parentItem?.data?.data;
|
||||
}
|
||||
|
||||
if (tableSchema && fieldInterface === 'm2o') {
|
||||
itemParams['service'] = tableSchema['x-component-props'].service;
|
||||
itemParams['collectionName'] = cm.getCollection(tableSchema['x-collection-field']).name;
|
||||
const childrenItem = await api.request({
|
||||
url: itemParams['collectionName'] + ':list',
|
||||
params,
|
||||
});
|
||||
itemParams['childrenTitleField'] = cm.getCollection(itemParams['collectionName']).titleField;
|
||||
itemParams['childrenOptions'] = childrenItem?.data?.data;
|
||||
|
||||
if (itemParams['parentOptions']?.length && itemParams['childrenOptions']?.length) {
|
||||
itemParams['parentOptions'].forEach((parentItem) => {
|
||||
const items = itemParams['childrenOptions']
|
||||
.map((item) => {
|
||||
if (item[quickAddParentField?.value]?.id === parentItem.id) {
|
||||
return {
|
||||
...item,
|
||||
label: item[itemParams['childrenTitleField']],
|
||||
keys: item.id,
|
||||
value: item.id,
|
||||
checked: false,
|
||||
};
|
||||
}
|
||||
})
|
||||
.filter(Boolean);
|
||||
if (!items.length) return;
|
||||
optionsItem.push({
|
||||
...parentItem,
|
||||
value: parentItem?.id,
|
||||
label: parentItem[itemParams['parentTitleField']],
|
||||
key: parentItem.id,
|
||||
childrenItems: items,
|
||||
});
|
||||
});
|
||||
} else if (
|
||||
itemParams['childrenOptions']?.length &&
|
||||
(!quickAddParentField || quickAddParentField?.value === 'none')
|
||||
) {
|
||||
itemParams['childrenOptions'].forEach((item) => {
|
||||
optionsItem.push({
|
||||
...item,
|
||||
label: item[itemParams['childrenTitleField']],
|
||||
value: item?.id,
|
||||
key: item?.id,
|
||||
checked: false,
|
||||
});
|
||||
});
|
||||
}
|
||||
setOptions(optionsItem);
|
||||
setDefOptions(optionsItem);
|
||||
} else if (tableSchema) {
|
||||
const fieldItem = cm.getCollectionField(tableSchema['x-collection-field']);
|
||||
if (!fieldItem?.uiSchema || !fieldItem?.uiSchema.enum) return;
|
||||
fieldItem.uiSchema.enum.forEach((item) => {
|
||||
optionsItem.push(item);
|
||||
});
|
||||
setOptions(optionsItem);
|
||||
setDefOptions(optionsItem);
|
||||
}
|
||||
}
|
||||
}, [fieldServiceFilter, fieldSchema, changeForm]);
|
||||
|
||||
useDeepCompareEffect(() => {
|
||||
if (!defOptions.length) return;
|
||||
const fieldTabs = field.value;
|
||||
if (quickAddParentField && quickAddParentField?.value !== 'none') {
|
||||
const filterParantOptions = tabsParantFilterOptions(defOptions, fieldTabs, quickAddField);
|
||||
const filterOptions = tabsParantFilterOptions(options, fieldTabs, quickAddField);
|
||||
setDefOptions(filterParantOptions);
|
||||
setOptions(filterOptions);
|
||||
} else {
|
||||
const filterDefOptions = tabsFilterOptions(options, fieldTabs, quickAddField);
|
||||
setDefOptions(filterDefOptions);
|
||||
const filterOptions = tabsFilterOptions(options, fieldTabs, quickAddField);
|
||||
setOptions(filterOptions);
|
||||
}
|
||||
}, [quickAddField, fieldValue]);
|
||||
|
||||
useFormEffects(() => {
|
||||
onFieldChange(formFieldFilter, (field) => {
|
||||
setChangeForm(field);
|
||||
});
|
||||
});
|
||||
const onSelect = (value) => {
|
||||
if (quickAddParentField && quickAddParentField.value !== 'none') {
|
||||
const filterOption = defOptions
|
||||
.map((item) => {
|
||||
const filterItem = item?.childrenItems?.filter((childrenItem) => childrenItem?.label?.includes(value));
|
||||
if (item?.label?.includes(value) || filterItem.length) {
|
||||
return {
|
||||
...item,
|
||||
childrenItems: filterItem.length ? filterItem : item.childrenItems,
|
||||
};
|
||||
}
|
||||
})
|
||||
.filter(Boolean);
|
||||
setOptions(filterOption);
|
||||
} else {
|
||||
const filterOption = defOptions.filter((item) => item?.label?.includes(value));
|
||||
setOptions(filterOption);
|
||||
}
|
||||
};
|
||||
|
||||
const onChange = (item) => {
|
||||
field.value = field.value || [];
|
||||
const addItem = {};
|
||||
addItem[quickAddField] = item;
|
||||
field.value.push(markRecordAsNew(addItem));
|
||||
setFieldValue([...field.value]);
|
||||
};
|
||||
|
||||
return isQuickAdd && quickAddField && quickAddField !== 'none' ? (
|
||||
<div>
|
||||
<Input
|
||||
placeholder={t('Please enter search content')}
|
||||
prefix={<SearchOutlined />}
|
||||
onChange={(e) => {
|
||||
onSelect(e.target.value);
|
||||
}}
|
||||
/>
|
||||
|
||||
{quickAddParentField && quickAddParentField?.value !== 'none' ? (
|
||||
<>
|
||||
{options.length ? (
|
||||
<Tabs
|
||||
tabPosition="left"
|
||||
items={options.map((item) => ({
|
||||
...item,
|
||||
children: (
|
||||
<Space>
|
||||
{item?.childrenItems?.map((childrenitem, index) => (
|
||||
<Button
|
||||
key={index}
|
||||
onClick={() => {
|
||||
onChange(childrenitem);
|
||||
}}
|
||||
icon={childrenitem.checked ? <CheckOutlined /> : null}
|
||||
>
|
||||
{childrenitem.label}
|
||||
</Button>
|
||||
))}
|
||||
</Space>
|
||||
),
|
||||
}))}
|
||||
style={{ height: '30vh', overflow: 'auto', padding: '10px' }}
|
||||
></Tabs>
|
||||
) : null}
|
||||
</>
|
||||
) : (
|
||||
<Space style={{ height: '30vh', overflow: 'auto', padding: '10px' }}>
|
||||
{options.map((item, index) => (
|
||||
<Button
|
||||
key={index}
|
||||
onClick={() => {
|
||||
onChange(item);
|
||||
}}
|
||||
icon={item.checked ? <CheckOutlined /> : null}
|
||||
>
|
||||
{item.label}
|
||||
</Button>
|
||||
))}
|
||||
</Space>
|
||||
)}
|
||||
</div>
|
||||
) : null;
|
||||
});
|
||||
|
||||
const tabsParantFilterOptions = (options, fieldTabs, arrayField) => {
|
||||
const filterOptions = options?.map((oItem) => {
|
||||
const filterItem = oItem.childrenItems.map((childrenItem) => {
|
||||
const fieldTabsValue = fieldTabs.find((item) => item[arrayField]?.value === childrenItem.value);
|
||||
return {
|
||||
...childrenItem,
|
||||
checked: fieldTabsValue ? true : false,
|
||||
};
|
||||
});
|
||||
return {
|
||||
...oItem,
|
||||
childrenItems: filterItem,
|
||||
};
|
||||
});
|
||||
return filterOptions;
|
||||
};
|
||||
|
||||
const tabsFilterOptions = (optitons, filterTabs, arrayField) => {
|
||||
const filterOptions = optitons.map((item) => {
|
||||
const filterValue = filterTabs.find((filterTabsItem) => filterTabsItem[arrayField]?.value === item.value);
|
||||
return {
|
||||
...item,
|
||||
checked: filterValue ? true : false,
|
||||
};
|
||||
});
|
||||
return filterOptions;
|
||||
};
|
@ -0,0 +1,58 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { DEBOUNCE_WAIT, isVariable, mergeFilter, useParseDataScopeFilter } from '@tachybase/client';
|
||||
import { reaction } from '@tachybase/schema';
|
||||
import { flatten, getValuesByPath } from '@tachybase/utils/client';
|
||||
|
||||
import _ from 'lodash';
|
||||
|
||||
import { getPath } from '../../../../variables/utils/getPath';
|
||||
import { getVariableName } from '../../../../variables/utils/getVariableName';
|
||||
|
||||
export const useFieldServiceFilter = (filter, originalFilter?) => {
|
||||
const [fieldServiceFilter, setFieldServiceFilter] = useState(null);
|
||||
const { parseFilter, findVariable } = useParseDataScopeFilter();
|
||||
|
||||
useEffect(() => {
|
||||
const filterFromSchema = filter;
|
||||
|
||||
const _run = async () => {
|
||||
const result = await parseFilter(mergeFilter([filterFromSchema || originalFilter]));
|
||||
setFieldServiceFilter(result);
|
||||
};
|
||||
const run = _.debounce(_run, DEBOUNCE_WAIT);
|
||||
|
||||
_run();
|
||||
|
||||
const dispose = reaction(() => {
|
||||
// 这一步主要是为了使 reaction 能够收集到依赖
|
||||
const flat = flatten(filterFromSchema, {
|
||||
breakOn({ key }) {
|
||||
return key.startsWith('$') && key !== '$and' && key !== '$or';
|
||||
},
|
||||
transformValue(value) {
|
||||
if (!isVariable(value)) {
|
||||
return value;
|
||||
}
|
||||
const variableName = getVariableName(value);
|
||||
const variable = findVariable(variableName);
|
||||
|
||||
if (process.env.NODE_ENV !== 'production' && !variable) {
|
||||
throw new Error(`useServiceOptions: can not find variable ${variableName}`);
|
||||
}
|
||||
|
||||
const result = getValuesByPath(
|
||||
{
|
||||
[variableName]: variable?.ctx || {},
|
||||
},
|
||||
getPath(value),
|
||||
);
|
||||
return result;
|
||||
},
|
||||
});
|
||||
return flat;
|
||||
}, run);
|
||||
|
||||
return dispose;
|
||||
}, [filter, findVariable, originalFilter, parseFilter]);
|
||||
return [fieldServiceFilter, setFieldServiceFilter];
|
||||
};
|
@ -13,6 +13,7 @@ import {
|
||||
useCollectionField_deprecated,
|
||||
useCollectionManager_deprecated,
|
||||
} from '../../../collection-manager';
|
||||
import { useCollection, useCollectionManager } from '../../../data-source';
|
||||
import { useRecord } from '../../../record-provider';
|
||||
import { useColumnSchema } from '../../../schema-component/antd/table-v2/Table.Column.Decorator';
|
||||
import { generalSettingsItems } from '../../../schema-items/GeneralSettings';
|
||||
@ -305,6 +306,177 @@ export const formItemSettings = new SchemaSettings({
|
||||
return form && !isFormReadPretty && validateSchema;
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'isquickaddtabs',
|
||||
type: 'switch',
|
||||
useVisible() {
|
||||
const readPretty = useIsFieldReadPretty();
|
||||
const isAssociationField = useIsAssociationField();
|
||||
const fieldMode = useFieldMode();
|
||||
return !readPretty && isAssociationField && ['SubTable'].includes(fieldMode);
|
||||
},
|
||||
|
||||
useComponentProps() {
|
||||
const { t } = useTranslation();
|
||||
const field = useField<Field>();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const { dn, refresh } = useDesignable();
|
||||
return {
|
||||
title: t('Is Quick Add Tabs'),
|
||||
checked: fieldSchema['x-component-props']?.isQuickAdd || false,
|
||||
onChange(value) {
|
||||
const schema = {
|
||||
['x-uid']: fieldSchema['x-uid'],
|
||||
};
|
||||
field.componentProps['isQuickAdd'] = value;
|
||||
fieldSchema['x-component-props'] = fieldSchema['x-component-props'] || {};
|
||||
fieldSchema['x-component-props']['isQuickAdd'] = value;
|
||||
schema['x-component-props'] = fieldSchema['x-component-props'];
|
||||
dn.emit('patch', {
|
||||
schema,
|
||||
});
|
||||
refresh();
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'setquickaddtabs',
|
||||
type: 'select',
|
||||
useComponentProps() {
|
||||
const { t } = useTranslation();
|
||||
const field = useField<Field>();
|
||||
const compile = useCompile();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const cm = useCollectionManager();
|
||||
const options = cm.getCollection(fieldSchema['x-collection-field']);
|
||||
const defVal = fieldSchema['x-component-props']['quickAddField'] || 'none';
|
||||
const { dn } = useDesignable();
|
||||
const isAddNewForm = useIsAddNewForm();
|
||||
const fieldTabsOptions = options.fields
|
||||
.map((item) => {
|
||||
if (item.interface === 'm2o' || item.interface === 'select') {
|
||||
return {
|
||||
...item,
|
||||
label: compile(item.uiSchema?.title),
|
||||
value: item.name,
|
||||
};
|
||||
}
|
||||
})
|
||||
.filter(Boolean);
|
||||
fieldTabsOptions.unshift({
|
||||
label: 'none',
|
||||
value: 'none',
|
||||
});
|
||||
return {
|
||||
title: t('Set Quick Add Tabs'),
|
||||
options: fieldTabsOptions,
|
||||
value: defVal,
|
||||
onChange(mode) {
|
||||
const schema = {
|
||||
['x-uid']: fieldSchema['x-uid'],
|
||||
};
|
||||
fieldSchema['x-component-props'] = fieldSchema['x-component-props'] || {};
|
||||
fieldSchema['x-component-props']['quickAddField'] = {
|
||||
fieldInterface: fieldTabsOptions.find((item) => item.value === mode)['interface'] || 'none',
|
||||
value: mode,
|
||||
};
|
||||
schema['x-component-props'] = fieldSchema['x-component-props'];
|
||||
field.componentProps = field.componentProps || {};
|
||||
field.componentProps['quickAddField'] = fieldSchema['x-component-props']['quickAddField'];
|
||||
|
||||
// 子表单状态不允许设置默认值
|
||||
if (isSubMode(fieldSchema) && isAddNewForm) {
|
||||
// @ts-ignore
|
||||
schema.default = null;
|
||||
fieldSchema.default = null;
|
||||
field.setInitialValue(null);
|
||||
field.setValue(null);
|
||||
}
|
||||
|
||||
void dn.emit('patch', {
|
||||
schema,
|
||||
});
|
||||
dn.refresh();
|
||||
},
|
||||
};
|
||||
},
|
||||
useVisible() {
|
||||
const fieldSchema = useFieldSchema();
|
||||
return fieldSchema['x-component-props']['isQuickAdd'];
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'setquickaddparenttabs',
|
||||
type: 'select',
|
||||
useComponentProps() {
|
||||
const { t } = useTranslation();
|
||||
const field = useField<Field>();
|
||||
const compile = useCompile();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const cm = useCollectionManager();
|
||||
const { value: quickField } = fieldSchema['x-component-props']?.['quickAddField'] || {};
|
||||
const options = cm.getCollectionFields(`${fieldSchema['x-collection-field']}.${quickField}`);
|
||||
const { dn } = useDesignable();
|
||||
const isAddNewForm = useIsAddNewForm();
|
||||
const fieldTabsOptions = options
|
||||
.map((item) => {
|
||||
if (item.interface === 'm2o')
|
||||
return {
|
||||
...item,
|
||||
label: compile(item.uiSchema.title),
|
||||
value: item.name,
|
||||
};
|
||||
})
|
||||
.filter(Boolean);
|
||||
fieldTabsOptions.unshift({
|
||||
label: t('none'),
|
||||
value: 'none',
|
||||
});
|
||||
const defValue = fieldSchema['x-component-props']?.['quickAddParentCollection']?.value || 'none';
|
||||
return {
|
||||
title: t('Set Quick Add Parent Tabs'),
|
||||
options: fieldTabsOptions,
|
||||
value: defValue,
|
||||
onChange(mode) {
|
||||
const schema = {
|
||||
['x-uid']: fieldSchema['x-uid'],
|
||||
};
|
||||
fieldSchema['x-component-props'] = fieldSchema['x-component-props'] || {};
|
||||
fieldSchema['x-component-props']['quickAddParentCollection'] = {
|
||||
collectionField: `${fieldSchema['x-collection-field']}.${quickField}.${mode}`,
|
||||
value: mode,
|
||||
};
|
||||
schema['x-component-props'] = fieldSchema['x-component-props'];
|
||||
field.componentProps = field.componentProps || {};
|
||||
field.componentProps['quickAddParentCollection'] = {
|
||||
collectionField: `${fieldSchema['x-collection-field']}.${quickField}.${mode}`,
|
||||
value: mode,
|
||||
};
|
||||
// 子表单状态不允许设置默认值
|
||||
if (isSubMode(fieldSchema) && isAddNewForm) {
|
||||
// @ts-ignore
|
||||
schema.default = null;
|
||||
fieldSchema.default = null;
|
||||
field.setInitialValue(null);
|
||||
field.setValue(null);
|
||||
}
|
||||
void dn.emit('patch', {
|
||||
schema,
|
||||
});
|
||||
dn.refresh();
|
||||
},
|
||||
};
|
||||
},
|
||||
useVisible() {
|
||||
const fieldSchema = useFieldSchema();
|
||||
return (
|
||||
fieldSchema['x-component-props']['isQuickAdd'] &&
|
||||
fieldSchema['x-component-props']['quickAddField'] &&
|
||||
fieldSchema['x-component-props']['quickAddField'] !== 'none'
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'defaultValue',
|
||||
Component: SchemaSettingsDefaultValue,
|
||||
|
@ -46,7 +46,7 @@ const useArrayField = (props) => {
|
||||
return (props.field || field) as ArrayField;
|
||||
};
|
||||
|
||||
const useTableColumns = (props: { showDel?: boolean; isSubTable?: boolean }) => {
|
||||
const useTableColumns = (props: { showDel?: boolean; isSubTable?: boolean; setFieldValue?: any }) => {
|
||||
const { t } = useTranslation();
|
||||
const { styles } = useStyles();
|
||||
const field = useArrayField(props);
|
||||
@ -162,6 +162,7 @@ const useTableColumns = (props: { showDel?: boolean; isSubTable?: boolean }) =>
|
||||
});
|
||||
field.value.splice(index, 1);
|
||||
field.initialValue?.splice(index, 1);
|
||||
props.setFieldValue([...field.value]);
|
||||
return field.onInput(field.value);
|
||||
});
|
||||
}}
|
||||
|
Loading…
Reference in New Issue
Block a user