diff --git a/packages/plugins/@hera/plugin-core/src/client/schema-components/association-cascader/AssociationCascader.tsx b/packages/plugins/@hera/plugin-core/src/client/schema-components/association-cascader/AssociationCascader.tsx index 1dace2bc0..2cf535b15 100644 --- a/packages/plugins/@hera/plugin-core/src/client/schema-components/association-cascader/AssociationCascader.tsx +++ b/packages/plugins/@hera/plugin-core/src/client/schema-components/association-cascader/AssociationCascader.tsx @@ -24,38 +24,88 @@ const AssociationCascader = connect((props) => { }); const options = useMemo(() => { - const dict: { [key: string]: string[] } = - data?.data.reduce((acc, item) => { - if (item[associationField]) { - const key = item[associationField][joinTitleField]; - acc[key] ??= []; - acc[key].push(item[titleField]); + if (props.chartCascader) { + const dataOptions = {}; + const options = []; + data?.data.forEach((item) => { + if (item?.[associationField]) { + const field = []; + if (Array.isArray(item[associationField]) && item[associationField].length) { + field.push(...item[associationField]); + } else { + field.push({ ...item[associationField] }); + } + field.forEach((fieldItem) => { + if (!Object.keys(fieldItem).length) return; + if (dataOptions[fieldItem[joinTitleField]]) { + dataOptions[fieldItem[joinTitleField]].push({ + label: item[titleField], + value: item[titleField], + }); + } else { + dataOptions[fieldItem[joinTitleField]] = [ + { + label: item[titleField], + value: item[titleField], + }, + ]; + } + }); } - return acc; - }, {}) || {}; - const options = Object.entries(dict).map(([key, values]) => ({ - [fieldNames.label]: key, - [fieldNames.value]: key, - children: values.map((value) => ({ [fieldNames.label]: value, [fieldNames.value]: value })), - })); - return options; + }); + for (const key in dataOptions) { + options.push({ + label: key, + value: key, + children: [...dataOptions[key]], + }); + } + return options; + } else { + const dict: { [key: string]: string[] } = + data?.data.reduce((acc, item) => { + if (item[associationField]) { + const key = item[associationField][joinTitleField]; + acc[key] ??= []; + acc[key].push(item[titleField]); + } + return acc; + }, {}) || {}; + const options = Object.entries(dict).map(([key, values]) => ({ + [fieldNames.label]: key, + [fieldNames.value]: key, + children: values.map((value) => ({ [fieldNames.label]: value, [fieldNames.value]: value })), + })); + return options; + } }, [associationField, joinTitleField, titleField, data?.data]); - return ; + + return ( + + ); }); const SingleValueCascader = (props) => { - const { value, options, onChange, fieldNames } = props; + const { value, options, onChange, fieldNames, chartCascader, titleField, joinTitleField } = props; + const fieldLabel = fieldNames ? fieldNames.value : titleField; + const joinFieldLabel = fieldNames ? fieldNames.value : 'value'; const arrayValue = value && options ? [] : undefined; if (arrayValue) { for (const option of options) { - if (option[fieldNames.value] === value) { - arrayValue.push(option[fieldNames.value]); + if (option[fieldLabel] === value) { + arrayValue.push(option[fieldLabel]); break; } for (const subOption of option.children) { - if (subOption[fieldNames.value] === value) { - arrayValue.push(option[fieldNames.value]); - arrayValue.push(subOption[fieldNames.value]); + if (subOption[joinFieldLabel] === value) { + arrayValue.push(option[joinFieldLabel]); + arrayValue.push(subOption[joinFieldLabel]); break; } } diff --git a/packages/plugins/@nocobase/plugin-data-visualization/src/client/filter/FilterItemInitializers.tsx b/packages/plugins/@nocobase/plugin-data-visualization/src/client/filter/FilterItemInitializers.tsx index 9534a7558..ab6a1ddde 100644 --- a/packages/plugins/@nocobase/plugin-data-visualization/src/client/filter/FilterItemInitializers.tsx +++ b/packages/plugins/@nocobase/plugin-data-visualization/src/client/filter/FilterItemInitializers.tsx @@ -22,6 +22,7 @@ import { useDesignable, useGlobalTheme, useSchemaInitializerItem, + useCompile, } from '@nocobase/client'; import { useMemoizedFn } from 'ahooks'; import { Alert, ConfigProvider, Typography } from 'antd'; @@ -35,7 +36,7 @@ const { Paragraph, Text } = Typography; const FieldComponentProps: React.FC = observer( (props) => { const form = useForm(); - const schema = getPropsSchemaByComponent(form.values.component); + const schema = getPropsSchemaByComponent(form.values.component, props['allCollection']); return schema ? : null; }, { displayName: 'FieldComponentProps' }, @@ -127,12 +128,31 @@ export const ChartFilterCustomItemInitializer: React.FC<{ const dm = useDataSourceManager(); const sourceFields = useChartFilterSourceFields(); const { options: fieldComponents, values: fieldComponentValues } = useFieldComponents(); + const { collections, getCollectionFields } = useCollectionManager_deprecated(); + const compile = useCompile(); + const allCollection = collections.map((collection) => { + return { + label: collection.getOption('title'), + value: collection.getOption('name'), + }; + }); const handleClick = useCallback(async () => { const values = await FormDialog( t('Add custom field'), () => ( { + return { + label: compile(field.uiSchema.title), + value: field.name, + }; + }); + }, + }} components={{ ...components, FieldComponentProps }} > @@ -176,6 +196,9 @@ export const ChartFilterCustomItemInitializer: React.FC<{ type: 'object', title: t('Component properties'), 'x-component': 'FieldComponentProps', + 'x-component-props': { + allCollection, + }, }, }, }} @@ -242,6 +265,7 @@ export const ChartFilterCustomItemInitializer: React.FC<{ 'x-component-props': { ...(defaultSchema['x-component-props'] || {}), ...props, + chartCascader: true, }, }), ); diff --git a/packages/plugins/@nocobase/plugin-data-visualization/src/client/filter/utils.ts b/packages/plugins/@nocobase/plugin-data-visualization/src/client/filter/utils.ts index d018de38a..37a0288eb 100644 --- a/packages/plugins/@nocobase/plugin-data-visualization/src/client/filter/utils.ts +++ b/packages/plugins/@nocobase/plugin-data-visualization/src/client/filter/utils.ts @@ -55,7 +55,7 @@ export const getOptionsSchema = () => { return options; }; -export const getPropsSchemaByComponent = (component: string) => { +export const getPropsSchemaByComponent = (component: string, allCollection) => { const showTime = { type: 'boolean', 'x-content': '{{ t("Show time") }}', @@ -135,6 +135,34 @@ export const getPropsSchemaByComponent = (component: string) => { options, }, }, + AssociationCascader: { + type: 'object', + properties: { + collection: { + type: 'string', + title: '{{t("Field collection")}}', + 'x-decorator': 'FormItem', + 'x-component': 'Select', + enum: allCollection, + }, + associationField: { + type: 'string', + title: '{{t("Field Association")}}', + 'x-visible': false, + 'x-decorator': 'FormItem', + 'x-component': 'Select', + 'x-reactions': { + dependencies: ['component', '.collection'], + fulfill: { + schema: { + 'x-visible': "{{$deps[0]=== 'AssociationCascader' && $deps[1]}}", + enum: '{{useCollectionField($deps[1])}}', + }, + }, + }, + }, + }, + }, }; return propsSchema[component]; }; diff --git a/packages/plugins/@nocobase/plugin-data-visualization/src/client/hooks/filter.ts b/packages/plugins/@nocobase/plugin-data-visualization/src/client/hooks/filter.ts index ea29411a4..d4d83dcd5 100644 --- a/packages/plugins/@nocobase/plugin-data-visualization/src/client/hooks/filter.ts +++ b/packages/plugins/@nocobase/plugin-data-visualization/src/client/hooks/filter.ts @@ -507,6 +507,7 @@ export const useFieldComponents = () => { { label: t('Select'), value: 'Select' }, { label: t('Radio group'), value: 'Radio.Group' }, { label: t('Checkbox group'), value: 'Checkbox.Group' }, + { label: t('AssociationCascader'), value: 'AssociationCascader' }, // { label: t('China region'), value: 'chinaRegion' }, ]; return {