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",
|
"Designer properties": "Designer properties",
|
||||||
"Load": "Load",
|
"Load": "Load",
|
||||||
"Dump": "Dump",
|
"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": "存储",
|
"Dump": "存储",
|
||||||
"Sorry, the page you visited does not exist.": "对不起,您访问的页面不存在。",
|
"Sorry, the page you visited does not exist.": "对不起,您访问的页面不存在。",
|
||||||
"Back Home": "回到主页",
|
"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 { ArrayItems } from '@tachybase/components';
|
||||||
import { Field, ISchema, useField, useFieldSchema } from '@tachybase/schema';
|
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 { SchemaSettings } from '../../../../application/schema-settings/SchemaSettings';
|
||||||
import { useCollectionManager_deprecated, useSortFields } from '../../../../collection-manager';
|
import { useCollectionManager_deprecated, useSortFields } from '../../../../collection-manager';
|
||||||
import { useFieldComponentName } from '../../../../common/useFieldComponentName';
|
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 { isSubMode } from '../../../../schema-component/antd/association-field/util';
|
||||||
import { useIsAssociationField, useIsFieldReadPretty } from '../../../../schema-component/antd/form-item';
|
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({
|
export const subTablePopoverComponentFieldSettings = new SchemaSettings({
|
||||||
name: 'fieldSettings:component:SubTable',
|
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 {
|
import {
|
||||||
action,
|
action,
|
||||||
ArrayField,
|
ArrayField,
|
||||||
@ -7,11 +7,13 @@ import {
|
|||||||
observer,
|
observer,
|
||||||
RecursionField,
|
RecursionField,
|
||||||
useFieldSchema,
|
useFieldSchema,
|
||||||
|
useForm,
|
||||||
} from '@tachybase/schema';
|
} from '@tachybase/schema';
|
||||||
|
|
||||||
import { Button } from 'antd';
|
import { useAsyncEffect } from 'ahooks';
|
||||||
|
import { Button, Tabs } from 'antd';
|
||||||
import { createStyles } from 'antd-style';
|
import { createStyles } from 'antd-style';
|
||||||
import { unionBy, uniqBy } from 'lodash';
|
import { set, unionBy, uniqBy } from 'lodash';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -21,11 +23,12 @@ import {
|
|||||||
SchemaComponentOptions,
|
SchemaComponentOptions,
|
||||||
useActionContext,
|
useActionContext,
|
||||||
} from '../..';
|
} from '../..';
|
||||||
|
import { useAPIClient, useRequest } from '../../../api-client';
|
||||||
import { useCreateActionProps } from '../../../block-provider/hooks';
|
import { useCreateActionProps } from '../../../block-provider/hooks';
|
||||||
import { FormActiveFieldsProvider } from '../../../block-provider/hooks/useFormActiveFields';
|
import { FormActiveFieldsProvider } from '../../../block-provider/hooks/useFormActiveFields';
|
||||||
import { TableSelectorParamsProvider } from '../../../block-provider/TableSelectorProvider';
|
import { TableSelectorParamsProvider } from '../../../block-provider/TableSelectorProvider';
|
||||||
import { CollectionProvider_deprecated } from '../../../collection-manager';
|
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 { markRecordAsNew } from '../../../data-source/collection-record/isNewRecord';
|
||||||
import { FlagProvider } from '../../../flag-provider';
|
import { FlagProvider } from '../../../flag-provider';
|
||||||
import { useCompile } from '../../hooks';
|
import { useCompile } from '../../hooks';
|
||||||
@ -33,6 +36,7 @@ import { ActionContextProvider } from '../action';
|
|||||||
import { Table } from '../table-v2/Table';
|
import { Table } from '../table-v2/Table';
|
||||||
import { useAssociationFieldContext, useFieldNames } from './hooks';
|
import { useAssociationFieldContext, useFieldNames } from './hooks';
|
||||||
import { useTableSelectorProps } from './InternalPicker';
|
import { useTableSelectorProps } from './InternalPicker';
|
||||||
|
import { InternalTabs } from './SubTabs/InternamTabs';
|
||||||
import { getLabelFormatValue, useLabelUiSchema } from './util';
|
import { getLabelFormatValue, useLabelUiSchema } from './util';
|
||||||
|
|
||||||
const useStyles = createStyles(({ css }) => {
|
const useStyles = createStyles(({ css }) => {
|
||||||
@ -106,7 +110,7 @@ export const SubTable: any = observer(
|
|||||||
const compile = useCompile();
|
const compile = useCompile();
|
||||||
const labelUiSchema = useLabelUiSchema(collectionField, fieldNames?.label || 'label');
|
const labelUiSchema = useLabelUiSchema(collectionField, fieldNames?.label || 'label');
|
||||||
const recordV2 = useCollectionRecord();
|
const recordV2 = useCollectionRecord();
|
||||||
|
const [fieldValue, setFieldValue] = useState([]);
|
||||||
const move = (fromIndex: number, toIndex: number) => {
|
const move = (fromIndex: number, toIndex: number) => {
|
||||||
if (toIndex === undefined) return;
|
if (toIndex === undefined) return;
|
||||||
if (!isArr(field.value)) return;
|
if (!isArr(field.value)) return;
|
||||||
@ -122,6 +126,7 @@ export const SubTable: any = observer(
|
|||||||
return field.onInput(field.value);
|
return field.onInput(field.value);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
field.move = move;
|
field.move = move;
|
||||||
|
|
||||||
const options = useMemo(() => {
|
const options = useMemo(() => {
|
||||||
@ -172,11 +177,17 @@ export const SubTable: any = observer(
|
|||||||
const filter = list.length ? { $and: [{ [`${targetKey}.$ne`]: list }] } : {};
|
const filter = list.length ? { $and: [{ [`${targetKey}.$ne`]: list }] } : {};
|
||||||
return filter;
|
return filter;
|
||||||
};
|
};
|
||||||
|
const tabsProps = {
|
||||||
|
...props,
|
||||||
|
fieldValue,
|
||||||
|
setFieldValue,
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<FlagProvider isInSubTable>
|
<FlagProvider isInSubTable>
|
||||||
<CollectionRecordProvider record={null} parentRecord={recordV2}>
|
<CollectionRecordProvider record={null} parentRecord={recordV2}>
|
||||||
<FormActiveFieldsProvider name="nester">
|
<FormActiveFieldsProvider name="nester">
|
||||||
|
<InternalTabs {...tabsProps} />
|
||||||
<Table
|
<Table
|
||||||
className={styles.table}
|
className={styles.table}
|
||||||
bordered
|
bordered
|
||||||
@ -185,6 +196,7 @@ export const SubTable: any = observer(
|
|||||||
showIndex
|
showIndex
|
||||||
dragSort={field.editable}
|
dragSort={field.editable}
|
||||||
showDel={field.editable}
|
showDel={field.editable}
|
||||||
|
setFieldValue={setFieldValue}
|
||||||
pagination={!!field.componentProps.pagination}
|
pagination={!!field.componentProps.pagination}
|
||||||
rowSelection={{ type: 'none', hideSelectAll: true }}
|
rowSelection={{ type: 'none', hideSelectAll: true }}
|
||||||
footer={() =>
|
footer={() =>
|
||||||
@ -198,6 +210,7 @@ export const SubTable: any = observer(
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
field.value = field.value || [];
|
field.value = field.value || [];
|
||||||
field.value.push(markRecordAsNew({}));
|
field.value.push(markRecordAsNew({}));
|
||||||
|
setFieldValue([...field.value]);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t('Add new')}
|
{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,
|
useCollectionField_deprecated,
|
||||||
useCollectionManager_deprecated,
|
useCollectionManager_deprecated,
|
||||||
} from '../../../collection-manager';
|
} from '../../../collection-manager';
|
||||||
|
import { useCollection, useCollectionManager } from '../../../data-source';
|
||||||
import { useRecord } from '../../../record-provider';
|
import { useRecord } from '../../../record-provider';
|
||||||
import { useColumnSchema } from '../../../schema-component/antd/table-v2/Table.Column.Decorator';
|
import { useColumnSchema } from '../../../schema-component/antd/table-v2/Table.Column.Decorator';
|
||||||
import { generalSettingsItems } from '../../../schema-items/GeneralSettings';
|
import { generalSettingsItems } from '../../../schema-items/GeneralSettings';
|
||||||
@ -305,6 +306,177 @@ export const formItemSettings = new SchemaSettings({
|
|||||||
return form && !isFormReadPretty && validateSchema;
|
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',
|
name: 'defaultValue',
|
||||||
Component: SchemaSettingsDefaultValue,
|
Component: SchemaSettingsDefaultValue,
|
||||||
|
@ -46,7 +46,7 @@ const useArrayField = (props) => {
|
|||||||
return (props.field || field) as ArrayField;
|
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 { t } = useTranslation();
|
||||||
const { styles } = useStyles();
|
const { styles } = useStyles();
|
||||||
const field = useArrayField(props);
|
const field = useArrayField(props);
|
||||||
@ -162,6 +162,7 @@ const useTableColumns = (props: { showDel?: boolean; isSubTable?: boolean }) =>
|
|||||||
});
|
});
|
||||||
field.value.splice(index, 1);
|
field.value.splice(index, 1);
|
||||||
field.initialValue?.splice(index, 1);
|
field.initialValue?.splice(index, 1);
|
||||||
|
props.setFieldValue([...field.value]);
|
||||||
return field.onInput(field.value);
|
return field.onInput(field.value);
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
|
Loading…
Reference in New Issue
Block a user