From 65a579384ad7d15b62baa0c68509e5d8182b650c Mon Sep 17 00:00:00 2001 From: Dunqing Date: Wed, 1 Feb 2023 12:55:46 +0800 Subject: [PATCH] feat(calendar): startDate and endDate support the use of association fields (#1397) * feat(calendar): startDate and endDate support the use of association fields * feat: improve association type --- .../hooks/useCollectionManager.ts | 56 +++++++++++++++++-- .../antd/calendar/Calendar.Designer.tsx | 34 ++++------- .../items/CalendarBlockInitializer.tsx | 54 ++++++++---------- .../src/schema-settings/SchemaSettings.tsx | 37 +++++++++++- 4 files changed, 118 insertions(+), 63 deletions(-) diff --git a/packages/core/client/src/collection-manager/hooks/useCollectionManager.ts b/packages/core/client/src/collection-manager/hooks/useCollectionManager.ts index 694538c25..2ea1d5206 100644 --- a/packages/core/client/src/collection-manager/hooks/useCollectionManager.ts +++ b/packages/core/client/src/collection-manager/hooks/useCollectionManager.ts @@ -1,11 +1,14 @@ import { clone } from '@formily/shared'; +import { CascaderProps } from 'antd'; import { reduce, unionBy, uniq } from 'lodash'; import { useContext } from 'react'; +import { useCompile } from '../../schema-component'; import { CollectionManagerContext } from '../context'; import { CollectionFieldOptions } from '../types'; export const useCollectionManager = () => { const { refreshCM, service, interfaces, collections, templates } = useContext(CollectionManagerContext); + const compile = useCompile() const getInheritedFields = (name) => { const inheritKeys = getInheritCollections(name); const inheritedFields = reduce( @@ -59,25 +62,65 @@ export const useCollectionManager = () => { }; const getChildrenCollections = (name) => { - const childrens = []; - const getChildrens = (name) => { + const children = []; + const getChildren = (name) => { const inheritCollections = collections.filter((v) => { return v.inherits?.includes(name); }); inheritCollections.forEach((v) => { const collectionKey = v.name; - childrens.push(v); - return getChildrens(collectionKey); + children.push(v); + return getChildren(collectionKey); }); - return childrens; + return children; }; - return getChildrens(name); + return getChildren(name); }; const getCurrentCollectionFields = (name: string) => { const collection = collections?.find((collection) => collection.name === name); return collection?.fields || []; }; + + const getCollectionFieldsOptions = (collectionName: string, type: string | string[] = 'string', opts?: { + /** + * 为 true 时允许查询所有关联字段 + * 为 Array 时仅允许查询指定的关联字段 + */ + association?: boolean | string[]; + }) => { + const { association = false } = opts || {}; + if (typeof type === 'string') { + type = [type]; + } + const fields = getCollectionFields(collectionName); + const options = fields + ?.filter( + (field) => + field.interface && + (type.includes(field.type) || (association && field.target && field.target !== collectionName && + Array.isArray(association) ? association.includes(field.interface) : false + )), + ) + ?.map((field) => { + const result: CascaderProps['options'][0] = { + value: field.name, + label: compile(field?.uiSchema?.title) || field.name, + }; + if (association && field.target) { + result.children = getCollectionFieldsOptions(field.target, type, opts); + if (!result.children?.length) { + return null + } + } + return result; + }) + // 过滤 map 产生为 null 的数据 + .filter(Boolean) + + return options; + }; + return { service, interfaces, @@ -91,6 +134,7 @@ export const useCollectionManager = () => { getInheritedFields, getCollectionField, getCollectionFields, + getCollectionFieldsOptions, getCurrentCollectionFields, getCollection(name: any) { if (typeof name !== 'string') { diff --git a/packages/core/client/src/schema-component/antd/calendar/Calendar.Designer.tsx b/packages/core/client/src/schema-component/antd/calendar/Calendar.Designer.tsx index 98c7d2071..32ac9a840 100644 --- a/packages/core/client/src/schema-component/antd/calendar/Calendar.Designer.tsx +++ b/packages/core/client/src/schema-component/antd/calendar/Calendar.Designer.tsx @@ -3,33 +3,19 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; import { useCompile, useDesignable } from '../..'; import { useCalendarBlockContext } from '../../../block-provider'; -import { useCollection } from '../../../collection-manager'; +import { useCollection, useCollectionManager } from '../../../collection-manager'; import { useCollectionFilterOptions } from '../../../collection-manager/action-hooks'; import { GeneralSchemaDesigner, SchemaSettings } from '../../../schema-settings'; import { useSchemaTemplate } from '../../../schema-templates'; -const useOptions = (type = 'string') => { - const compile = useCompile(); - const { fields } = useCollection(); - const options = fields - ?.filter((field) => field.type === type) - ?.map((field) => { - return { - value: field.name, - label: compile(field?.uiSchema?.title), - }; - }); - return options; -}; - export const CalendarDesigner = () => { const field = useField(); const fieldSchema = useFieldSchema(); - const { name, title, fields } = useCollection(); + const { name, title } = useCollection(); + const { getCollectionFieldsOptions } = useCollectionManager(); const dataSource = useCollectionFilterOptions(name); const { service } = useCalendarBlockContext(); const { dn } = useDesignable(); - const compile = useCompile(); const { t } = useTranslation(); const template = useSchemaTemplate(); const defaultFilter = fieldSchema?.['x-decorator-props']?.params?.filter || {}; @@ -41,7 +27,7 @@ export const CalendarDesigner = () => { { const fieldNames = field.decoratorProps.fieldNames || {}; fieldNames['title'] = title; @@ -74,10 +60,12 @@ export const CalendarDesigner = () => { dn.refresh(); }} /> - { const fieldNames = field.decoratorProps.fieldNames || {}; fieldNames['start'] = start; @@ -93,10 +81,12 @@ export const CalendarDesigner = () => { dn.refresh(); }} /> - { const fieldNames = field.decoratorProps.fieldNames || {}; fieldNames['end'] = end; diff --git a/packages/core/client/src/schema-initializer/items/CalendarBlockInitializer.tsx b/packages/core/client/src/schema-initializer/items/CalendarBlockInitializer.tsx index 4c808ab5a..a7815e0c3 100644 --- a/packages/core/client/src/schema-initializer/items/CalendarBlockInitializer.tsx +++ b/packages/core/client/src/schema-initializer/items/CalendarBlockInitializer.tsx @@ -1,18 +1,20 @@ -import React, { useContext } from "react"; -import { FormDialog, FormLayout } from "@formily/antd"; +import React, { useContext } from 'react'; +import { FormDialog, FormLayout } from '@formily/antd'; import { FormOutlined } from '@ant-design/icons'; -import { SchemaOptionsContext } from "@formily/react"; -import { useTranslation } from "react-i18next"; +import { SchemaOptionsContext } from '@formily/react'; +import { useTranslation } from 'react-i18next'; -import { useCollectionManager } from "../../collection-manager"; -import { SchemaComponent, SchemaComponentOptions } from "../../schema-component"; -import { createCalendarBlockSchema } from "../utils"; -import { DataBlockInitializer } from "./DataBlockInitializer"; +import { useCollection, useCollectionManager } from '../../collection-manager'; +import { SchemaComponent, SchemaComponentOptions, useCompile } from '../../schema-component'; +import { createCalendarBlockSchema } from '../utils'; +import { DataBlockInitializer } from './DataBlockInitializer'; +import { CascaderProps } from 'antd'; export const CalendarBlockInitializer = (props) => { const { insert } = props; const { t } = useTranslation(); - const { getCollectionFields } = useCollectionManager(); + const { getCollectionField, getCollectionFieldsOptions } = useCollectionManager(); + useCollectionManager; const options = useContext(SchemaOptionsContext); return ( { componentType={'Calendar'} icon={} onCreateBlockSchema={async ({ item }) => { - const collectionFields = getCollectionFields(item.name); - const stringFields = collectionFields - ?.filter((field) => field.type === 'string') - ?.map((field) => { - return { - label: field?.uiSchema?.title, - value: field.name, - }; - }); - const dateFields = collectionFields - ?.filter((field) => field.type === 'date') - ?.map((field) => { - return { - label: field?.uiSchema?.title, - value: field.name, - }; - }); + const stringFieldsOptions = getCollectionFieldsOptions(item.name, 'string'); + const dateFieldsOptions = getCollectionFieldsOptions(item.name, 'date', { + association: ['o2o', 'obo', 'oho', 'm2o'], + }); + const values = await FormDialog(t('Create calendar block'), () => { return ( @@ -46,23 +36,23 @@ export const CalendarBlockInitializer = (props) => { properties: { title: { title: t('Title field'), - enum: stringFields, + enum: stringFieldsOptions, required: true, 'x-component': 'Select', 'x-decorator': 'FormItem', }, start: { title: t('Start date field'), - enum: dateFields, + enum: dateFieldsOptions, required: true, - default: 'createdAt', - 'x-component': 'Select', + default: getCollectionField(`${item.name}.createdAt`) ? 'createdAt' : null, + 'x-component': 'Cascader', 'x-decorator': 'FormItem', }, end: { title: t('End date field'), - enum: dateFields, - 'x-component': 'Select', + enum: dateFieldsOptions, + 'x-component': 'Cascader', 'x-decorator': 'FormItem', }, }, diff --git a/packages/core/client/src/schema-settings/SchemaSettings.tsx b/packages/core/client/src/schema-settings/SchemaSettings.tsx index de4f3690b..bfafd55b6 100644 --- a/packages/core/client/src/schema-settings/SchemaSettings.tsx +++ b/packages/core/client/src/schema-settings/SchemaSettings.tsx @@ -3,7 +3,19 @@ import { FormDialog, FormItem, FormLayout, Input } from '@formily/antd'; import { createForm, Field, GeneralField } from '@formily/core'; import { ISchema, Schema, SchemaOptionsContext, useField, useFieldSchema, useForm } from '@formily/react'; import { uid } from '@formily/shared'; -import { Alert, Button, Dropdown, Menu, MenuItemProps, Modal, Select, Space, Switch } from 'antd'; +import { + Alert, + Button, + Cascader, + CascaderProps, + Dropdown, + Menu, + MenuItemProps, + Modal, + Select, + Space, + Switch, +} from 'antd'; import classNames from 'classnames'; import { cloneDeep } from 'lodash'; import React, { createContext, useContext, useMemo, useState } from 'react'; @@ -22,7 +34,7 @@ import { useAPIClient, useCollection, useCompile, - useDesignable + useDesignable, } from '..'; import { useSchemaTemplateManager } from '../schema-templates'; import { useBlockTemplateContext } from '../schema-templates/BlockTemplate'; @@ -61,6 +73,7 @@ type SchemaSettingsNested = { Divider?: React.FC; Popup?: React.FC; SwitchItem?: React.FC; + CascaderItem?: React.FC & Omit & { title: any }>; [key: string]: any; }; @@ -350,7 +363,7 @@ SchemaSettings.Item = (props) => { return ( { info.domEvent.preventDefault(); @@ -434,6 +447,24 @@ SchemaSettings.SelectItem = (props) => { ); }; +SchemaSettings.CascaderItem = (props: CascaderProps & { title: any }) => { + const { title, options, value, onChange, ...others } = props; + return ( + +
+ {title} + +
+
+ ); +}; + interface SwitchItemProps extends Omit { title: string; checked?: boolean;