feat: 新增自定义筛选组件,调整筛选字段内容 (#1468)
Co-authored-by: sealday <sealday@gmail.com> Reviewed-on: daoyoucloud/tachybase#1468 Co-authored-by: wjh <wwwjh0710@163.com> Co-committed-by: wjh <wwwjh0710@163.com>
This commit is contained in:
parent
7850cb3324
commit
f6ffc487c2
@ -423,14 +423,13 @@ export const useFilterBlockActionProps = () => {
|
||||
customValues: {},
|
||||
customFilter: {},
|
||||
};
|
||||
|
||||
if (Object.keys(form.values)?.includes('custom')) {
|
||||
if (Object.keys(form.values)?.includes('__custom')) {
|
||||
const values = { ...form.values };
|
||||
delete values['custom'];
|
||||
delete values['__custom'];
|
||||
filter.formValues = { ...values };
|
||||
for (const key in form.values['custom']) {
|
||||
if (form.values['custom'][key]) {
|
||||
filter.customValues[key] = form.values['custom'][key];
|
||||
for (const key in form.values['__custom']) {
|
||||
if (form.values['__custom'][key]) {
|
||||
filter.customValues[key] = form.values['__custom'][key];
|
||||
}
|
||||
}
|
||||
filter.customFilter = getCustomCondition(filter.customValues, fieldSchema);
|
||||
|
@ -25,5 +25,5 @@ export function useFieldComponentName(): string {
|
||||
field?.componentProps?.['mode'] ||
|
||||
(isFileField ? 'FileManager' : '') ||
|
||||
collectionField?.uiSchema?.['x-component'];
|
||||
return map[fieldComponentName] || fieldComponentName;
|
||||
return map[fieldComponentName] || fieldComponentName || fieldSchema['x-component-props']?.['component'];
|
||||
}
|
||||
|
@ -12,7 +12,6 @@ import {
|
||||
FilterCustomVariableInput,
|
||||
SchemaSettingCollection,
|
||||
SchemaSettingComponent,
|
||||
SchemaSettingsCustomRemove,
|
||||
SchemaSettingsDataScope,
|
||||
} from '../../../../schema-settings';
|
||||
|
||||
@ -111,7 +110,7 @@ export const FilterItemCustomSettings = new SchemaSettings({
|
||||
const field = useField();
|
||||
const { dn } = useDesignable();
|
||||
const fieldName = fieldSchema['name'] as string;
|
||||
const name = fieldName.includes('custom') ? fieldSchema['collectionName'] : fieldName;
|
||||
const name = fieldName.includes('__custom') ? fieldSchema['collectionName'] : fieldName;
|
||||
return {
|
||||
collectionName: name,
|
||||
defaultFilter: fieldSchema?.['x-component-props']?.params?.filter || {},
|
||||
@ -133,8 +132,7 @@ export const FilterItemCustomSettings = new SchemaSettings({
|
||||
},
|
||||
useVisible() {
|
||||
const fieldSchema = useFieldSchema();
|
||||
const component = fieldSchema['x-component'];
|
||||
return component !== 'Input';
|
||||
return fieldSchema?.['collectionName'];
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -152,7 +150,8 @@ export const FilterItemCustomSettings = new SchemaSettings({
|
||||
useVisible() {
|
||||
const fieldSchema = useFieldSchema();
|
||||
const component = fieldSchema['x-component'];
|
||||
return component === 'Select' || component === 'AutoComplete';
|
||||
const items = ['Select', 'AutoComplete', 'Radio.Group', 'Checkbox.Group'];
|
||||
return items.includes(component);
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -167,7 +166,7 @@ export const FilterItemCustomSettings = new SchemaSettings({
|
||||
const { dn } = useDesignable();
|
||||
const compile = useCompile();
|
||||
const collectionManage = useCollectionManager_deprecated();
|
||||
const isCustomFilterItem = ((fieldSchema?.name as string) ?? '').startsWith('custom.');
|
||||
const isCustomFilterItem = ((fieldSchema?.name as string) ?? '').startsWith('__custom.');
|
||||
const collectionManageField = isCustomFilterItem
|
||||
? collectionManage.collections.filter((value) => value.name === fieldSchema['x-decorator-props'])[0]
|
||||
: {};
|
||||
|
@ -15,7 +15,7 @@ export const filterFormItemInitializers_deprecated = new CompatibleSchemaInitial
|
||||
title: '{{t("Configure fields")}}',
|
||||
items: [
|
||||
{
|
||||
type: 'itemGroup',
|
||||
type: 'subMenu',
|
||||
name: 'displayFields',
|
||||
title: '{{t("Display fields")}}',
|
||||
useChildren: useFilterFormItemInitializerFields,
|
||||
@ -54,7 +54,7 @@ export const filterFormItemInitializers = new CompatibleSchemaInitializer(
|
||||
title: '{{t("Configure fields")}}',
|
||||
items: [
|
||||
{
|
||||
type: 'itemGroup',
|
||||
type: 'subMenu',
|
||||
name: 'displayFields',
|
||||
title: '{{t("Display fields")}}',
|
||||
useChildren: useFilterFormItemInitializerFields,
|
||||
|
@ -0,0 +1,49 @@
|
||||
import { Field, useField, useFieldSchema } from '@tachybase/schema';
|
||||
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { SchemaSettings } from '../../../../application/schema-settings/SchemaSettings';
|
||||
import { useDesignable } from '../../../../schema-component';
|
||||
import { useColumnSchema } from '../../../../schema-component/antd/table-v2/Table.Column.Decorator';
|
||||
|
||||
export const radioComponentFieldSettings = new SchemaSettings({
|
||||
name: 'fieldSettings:component:Radio group',
|
||||
items: [
|
||||
{
|
||||
name: 'fieldComponent',
|
||||
type: 'select',
|
||||
useComponentProps() {
|
||||
const { t } = useTranslation();
|
||||
const field = useField<Field>();
|
||||
const { fieldSchema: tableColumnSchema } = useColumnSchema();
|
||||
const schema = useFieldSchema();
|
||||
const fieldSchema = tableColumnSchema || schema;
|
||||
const fieldModeOptions = [
|
||||
{ label: t('Checkbox'), value: 'Checkbox' },
|
||||
{ label: t('Radio group'), value: 'Radio group' },
|
||||
];
|
||||
const { dn } = useDesignable();
|
||||
return {
|
||||
title: t('Field component'),
|
||||
options: fieldModeOptions,
|
||||
value: fieldSchema['x-component-props']?.mode || 'Radio group',
|
||||
onChange(mode) {
|
||||
const schema = {
|
||||
['x-uid']: fieldSchema['x-uid'],
|
||||
};
|
||||
fieldSchema['x-component-props'] = fieldSchema['x-component-props'] || {};
|
||||
fieldSchema['x-component-props']['mode'] = mode;
|
||||
schema['x-component-props'] = fieldSchema['x-component-props'];
|
||||
field.componentProps = field.componentProps || {};
|
||||
field.componentProps.mode = mode;
|
||||
|
||||
void dn.emit('patch', {
|
||||
schema,
|
||||
});
|
||||
dn.refresh();
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
@ -162,19 +162,22 @@ export const getCustomCondition = (filter, fieldSchema, customFlat = flat) => {
|
||||
for (const filterKey in filterSchemaItem) {
|
||||
const match = filterSchemaItem[filterKey]?.slice(11, -2);
|
||||
const collection = match?.split('.')[0];
|
||||
const filterItems = Object.keys(items).filter((item) => item.includes(collection))[0];
|
||||
if (filterItems) {
|
||||
filterSchemaItem[filterKey] = items[filterItems];
|
||||
const filterItems = Object.keys(items).filter((item) => item.includes(collection));
|
||||
if (filterItems.length > 1) {
|
||||
filterSchemaItem[filterKey] = filterItems.map((key) => items[key]);
|
||||
} else {
|
||||
filterSchemaItem[filterKey] = items[filterItems[0]];
|
||||
}
|
||||
}
|
||||
for (const item in filterSchemaItem) {
|
||||
if (filterSchemaItem[item].includes('$nFilter')) {
|
||||
if (!filterSchemaItem[item] || filterSchemaItem[item].includes('$nFilter')) {
|
||||
delete filterSchemaItem[item];
|
||||
}
|
||||
}
|
||||
const flatFieldSchema = customFlat.unflatten(filterSchemaItem);
|
||||
flatFieldSchema['$and'] = flatFieldSchema?.['$and']?.filter(Boolean);
|
||||
flatFieldSchema['$or'] = flatFieldSchema?.['$or']?.filter(Boolean);
|
||||
|
||||
return flatFieldSchema;
|
||||
} else {
|
||||
return customFlat.unflatten({});
|
||||
|
@ -508,36 +508,54 @@ export const EditOperator = () => {
|
||||
['x-filter-operators']: storedOperators,
|
||||
};
|
||||
let componentProps = {};
|
||||
|
||||
const isCustom = (fieldSchema.name as string).includes('__custom');
|
||||
// 根据操作符的配置,设置组件的属性
|
||||
if (operator?.schema?.['x-component']) {
|
||||
_.set(fieldSchema, 'x-component-props.component', operator.schema['x-component']);
|
||||
_.set(field, 'componentProps.component', operator.schema['x-component']);
|
||||
_.set(fieldSchema, isCustom ? 'x-component' : 'x-component-props.component', operator.schema['x-component']);
|
||||
_.set(field, isCustom ? 'component' : 'componentProps.component', operator.schema['x-component']);
|
||||
field.reset();
|
||||
componentProps = {
|
||||
component: operator.schema['x-component'],
|
||||
...operator.schema['x-component-props'],
|
||||
...operator.schema?.['x-component-props'],
|
||||
};
|
||||
dn.emit('patch', {
|
||||
const dnSchema = {
|
||||
schema: {
|
||||
['x-uid']: fieldSchema['x-uid'],
|
||||
['x-component-props']: componentProps,
|
||||
},
|
||||
});
|
||||
};
|
||||
if (isCustom) {
|
||||
dnSchema.schema['x-component'] = operator.schema?.['x-component'];
|
||||
dnSchema.schema['x-component-props']['component'] = fieldSchema['x-component-props']['component'];
|
||||
}
|
||||
dn.emit('patch', dnSchema);
|
||||
} else if (fieldSchema['x-component-props']?.component) {
|
||||
_.set(fieldSchema, 'x-component-props.component', null);
|
||||
_.set(field, 'componentProps.component', null);
|
||||
_.set(
|
||||
fieldSchema,
|
||||
isCustom ? 'x-component' : 'x-component-props.component',
|
||||
isCustom ? fieldSchema['x-component-props']?.component : null,
|
||||
);
|
||||
_.set(
|
||||
field,
|
||||
isCustom ? 'component' : 'componentProps.component',
|
||||
isCustom ? fieldSchema['x-component-props']?.component : null,
|
||||
);
|
||||
|
||||
field.reset();
|
||||
componentProps = {
|
||||
component: null,
|
||||
...operator.schema['x-component-props'],
|
||||
component: isCustom ? fieldSchema['x-component-props']?.component : null,
|
||||
...operator.schema?.['x-component-props'],
|
||||
};
|
||||
dn.emit('patch', {
|
||||
const dnSchema = {
|
||||
schema: {
|
||||
['x-uid']: fieldSchema['x-uid'],
|
||||
['x-component-props']: componentProps,
|
||||
},
|
||||
});
|
||||
};
|
||||
if (isCustom) {
|
||||
dnSchema.schema['x-component'] = fieldSchema['x-component-props']?.component;
|
||||
}
|
||||
dn.emit('patch', dnSchema);
|
||||
}
|
||||
|
||||
field.componentProps = componentProps;
|
||||
@ -559,7 +577,7 @@ export const EditTitleField = () => {
|
||||
const { dn } = useDesignable();
|
||||
const compile = useCompile();
|
||||
const collectionManage = useCollectionManager_deprecated();
|
||||
const isCustomFilterItem = ((fieldSchema?.name as string) ?? '').startsWith('custom.');
|
||||
const isCustomFilterItem = ((fieldSchema?.name as string) ?? '').startsWith('__custom.');
|
||||
const collectionManageField = isCustomFilterItem
|
||||
? collectionManage.collections.filter((value) => value.name === fieldSchema['x-decorator-props'])[0]
|
||||
: {};
|
||||
|
@ -27,9 +27,9 @@ const ObjectSelect = (props: Props) => {
|
||||
const form = useForm();
|
||||
|
||||
useEffect(() => {
|
||||
if (collectionName && fieldSchema['name'].toString().includes('custom') && defaultValue) {
|
||||
if (collectionName && fieldSchema['name'].toString().includes('__custom') && defaultValue) {
|
||||
const name = fieldSchema['name'].toString().split('.')[1];
|
||||
form.values['custom'][name] = defaultValue?.[fieldNames.value];
|
||||
form.values['__custom'][name] = defaultValue?.[fieldNames.value];
|
||||
}
|
||||
}, []);
|
||||
const toValue = (v: any) => {
|
||||
@ -94,9 +94,9 @@ const ObjectSelect = (props: Props) => {
|
||||
} else {
|
||||
onChange?.(current.shift() || null);
|
||||
}
|
||||
if (collectionName && fieldSchema['name'].toString().includes('custom')) {
|
||||
if (collectionName && fieldSchema['name'].toString().includes('__custom')) {
|
||||
const name = fieldSchema['name'].toString().split('.')[1];
|
||||
form.values['custom'][name] = changed?.['value'];
|
||||
form.values['__custom'][name] = changed?.['value'];
|
||||
}
|
||||
}}
|
||||
mode={mode}
|
||||
|
@ -43,7 +43,6 @@ import {
|
||||
GeneralSchemaDesigner,
|
||||
SchemaSettingCollection,
|
||||
SchemaSettingComponent,
|
||||
SchemaSettingsCustomRemove,
|
||||
SchemaSettingsDataScope,
|
||||
SchemaSettingsDivider,
|
||||
SchemaSettingsRemove,
|
||||
@ -58,20 +57,6 @@ const FieldComponentProps: React.FC = observer(
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
mode: {
|
||||
type: 'string',
|
||||
enum: [
|
||||
{
|
||||
label: '{{ t("Single select") }}',
|
||||
value: '',
|
||||
},
|
||||
],
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Radio.Group',
|
||||
'x-component-props': {
|
||||
defaultValue: '',
|
||||
},
|
||||
},
|
||||
options: {
|
||||
title: '{{t("Options")}}',
|
||||
type: 'array',
|
||||
@ -143,7 +128,9 @@ export const useFieldComponents = () => {
|
||||
{ label: t('AutoComplete'), value: 'AutoComplete' },
|
||||
{ label: t('Select'), value: 'Select' },
|
||||
{ label: t('AssociationCascader'), value: 'AssociationCascader' },
|
||||
// { label: t('CustomSelect***'), value: 'CustomSelect' },
|
||||
{ label: t('DatePicker'), value: 'DatePicker' },
|
||||
{ label: t('Radio group'), value: 'Radio.Group' },
|
||||
{ label: t('Checkbox group'), value: 'Checkbox.Group' },
|
||||
];
|
||||
return {
|
||||
options,
|
||||
@ -249,6 +236,16 @@ export const FilterCustomItemInitializer: React.FC<{
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'FieldComponentProps',
|
||||
'x-visible': false,
|
||||
'x-reactions': [
|
||||
{
|
||||
dependencies: ['component'],
|
||||
fulfill: {
|
||||
schema: {
|
||||
'x-visible': "{{$deps[0] === 'Radio.Group' || $deps[0]==='Checkbox.Group'}}",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
}}
|
||||
@ -286,35 +283,40 @@ export const FilterCustomItemInitializer: React.FC<{
|
||||
});
|
||||
},
|
||||
});
|
||||
const { title, component, collection, associationField } = values;
|
||||
const { title, component, collection, associationField, props } = values;
|
||||
const defaultSchema = getInterface(component)?.default?.uiSchema || {};
|
||||
const titleField = cm.getCollection(collection)?.titleField;
|
||||
const name = uid();
|
||||
insert(
|
||||
gridRowColWrap({
|
||||
...defaultSchema,
|
||||
type: 'string',
|
||||
title: title,
|
||||
name: 'custom.' + name,
|
||||
required: false,
|
||||
'x-component': component,
|
||||
'x-toolbar': 'FormItemSchemaToolbar',
|
||||
'x-settings': 'fieldSettings:FilterFormCustomSettings',
|
||||
'x-decorator': 'FilterFormItem',
|
||||
'x-decorator-props': collection,
|
||||
'x-component-props': {
|
||||
...(defaultSchema['x-component-props'] || {}),
|
||||
fieldNames: {
|
||||
label: titleField,
|
||||
value: titleField,
|
||||
},
|
||||
associationField,
|
||||
collection,
|
||||
objectValue: true,
|
||||
const schema = {
|
||||
...defaultSchema,
|
||||
type: 'string',
|
||||
title: title,
|
||||
name: '__custom.' + name,
|
||||
required: false,
|
||||
'x-component': component,
|
||||
'x-toolbar': 'FormItemSchemaToolbar',
|
||||
'x-settings': 'fieldSettings:FilterFormCustomSettings',
|
||||
'x-decorator': 'FilterFormItem',
|
||||
'x-decorator-props': collection,
|
||||
'x-component-props': {
|
||||
...(defaultSchema['x-component-props'] || {}),
|
||||
fieldNames: {
|
||||
label: titleField,
|
||||
value: titleField,
|
||||
},
|
||||
collectionName: collection,
|
||||
}),
|
||||
);
|
||||
associationField,
|
||||
collection,
|
||||
objectValue: true,
|
||||
component: component,
|
||||
...props,
|
||||
},
|
||||
collectionName: collection,
|
||||
};
|
||||
if (component === 'DatePicker') {
|
||||
schema['x-settings'] = 'fieldSettings:FilterFormItem';
|
||||
schema['x-designer-props'] = { interface: 'datetime' };
|
||||
}
|
||||
insert(gridRowColWrap(schema));
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [theme]);
|
||||
@ -330,7 +332,7 @@ export const FilterItemCustomDesigner: React.FC = () => {
|
||||
const { t } = useTranslation();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const fieldName = fieldSchema['name'] as string;
|
||||
const name = fieldName.includes('custom') ? fieldSchema['collectionName'] : fieldName;
|
||||
const name = fieldName.includes('__custom') ? fieldSchema['collectionName'] : fieldName;
|
||||
const { form } = useFormBlockContext();
|
||||
const field = useField();
|
||||
const { dn } = useDesignable();
|
||||
|
@ -8,7 +8,19 @@ import { SchemaSettingsSelectItem } from './SchemaSettings';
|
||||
export const SchemaSettingComponent = () => {
|
||||
const fieldSchema = useFieldSchema();
|
||||
const field = useField();
|
||||
const { options } = useFieldComponents();
|
||||
const checkedItems = ['Radio.Group', 'Checkbox.Group'];
|
||||
const component = fieldSchema['x-component'];
|
||||
const options = useFieldComponents()
|
||||
.options.map((item) => {
|
||||
if (checkedItems.includes(component)) {
|
||||
return checkedItems.includes(item.value) ? item : null;
|
||||
} else {
|
||||
return checkedItems.includes(item.value) || item.value === 'DatePicker' || item.value === 'AssociationCascader'
|
||||
? null
|
||||
: item;
|
||||
}
|
||||
})
|
||||
.filter(Boolean);
|
||||
const { dn } = useDesignable();
|
||||
return (
|
||||
<SchemaSettingsSelectItem
|
||||
|
@ -51,6 +51,7 @@ import { inputNumberComponentFieldSettings } from '../modules/fields/component/I
|
||||
import { subformComponentFieldSettings } from '../modules/fields/component/Nester/subformComponentFieldSettings';
|
||||
import { recordPickerComponentFieldSettings } from '../modules/fields/component/Picker/recordPickerComponentFieldSettings';
|
||||
import { subformPopoverComponentFieldSettings } from '../modules/fields/component/PopoverNester/subformPopoverComponentFieldSettings';
|
||||
import { radioComponentFieldSettings } from '../modules/fields/component/Radio/radioComponentFieldSettings';
|
||||
import { selectComponentFieldSettings } from '../modules/fields/component/Select/selectComponentFieldSettings';
|
||||
import { subTablePopoverComponentFieldSettings } from '../modules/fields/component/SubTable/subTablePopoverComponentFieldSettings';
|
||||
import { tagComponentFieldSettings } from '../modules/fields/component/Tag/tagComponentFieldSettings';
|
||||
@ -111,6 +112,7 @@ export class SchemaSettingsPlugin extends Plugin {
|
||||
this.schemaSettingsManager.add(unixTimestampComponentFieldSettings);
|
||||
this.schemaSettingsManager.add(inputNumberComponentFieldSettings);
|
||||
this.schemaSettingsManager.add(checkboxComponentFieldSettings);
|
||||
this.schemaSettingsManager.add(radioComponentFieldSettings);
|
||||
|
||||
this.schemaSettingsManager.add(fileManagerComponentFieldSettings);
|
||||
this.schemaSettingsManager.add(tagComponentFieldSettings);
|
||||
|
@ -28,10 +28,10 @@ export const useFilterVariable = (props: any = {}) => {
|
||||
});
|
||||
}
|
||||
const options = customFields
|
||||
.filter((value) => value?.props?.name.includes('custom.'))
|
||||
.filter((value) => value?.props?.name.includes('__custom.'))
|
||||
.map((custom) => {
|
||||
if (activeFields.includes(custom?.props?.name)) {
|
||||
const value = custom?.props?.name.replace(/^custom\./, '');
|
||||
const value = custom?.props?.name.replace(/^__custom\./, '');
|
||||
return {
|
||||
key: custom?.props?.name,
|
||||
value,
|
||||
|
@ -0,0 +1,15 @@
|
||||
import { Migration } from '../../../../../../core/server/src/migration';
|
||||
|
||||
export default class extends Migration {
|
||||
on = 'beforeLoad'; // 'beforeLoad' or 'afterLoad'
|
||||
appVersion = '<0.21.84';
|
||||
async up() {
|
||||
const result: any = await this.app.db.sequelize.query(`
|
||||
UPDATE public."uiSchemas"
|
||||
SET name = REPLACE(name, 'custom.', '__custom.')
|
||||
WHERE name LIKE 'custom.%';
|
||||
`);
|
||||
const count = result[1].rowCount || 0;
|
||||
console.log('共更新数据:' + count + '条');
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user