diff --git a/packages/client/src/locale/zh_CN.ts b/packages/client/src/locale/zh_CN.ts index 31ba62229..29b8f933b 100644 --- a/packages/client/src/locale/zh_CN.ts +++ b/packages/client/src/locale/zh_CN.ts @@ -287,5 +287,6 @@ export default { "Template name": "模板名称", "Block type": "区块类型", "Action column": "操作列", - "Records per page": "每页显示数量" + "Records per page": "每页显示数量", + "(Fields only)": "(仅字段)" } diff --git a/packages/client/src/schema-component/antd/form-v2/Form.Designer.tsx b/packages/client/src/schema-component/antd/form-v2/Form.Designer.tsx index 82841c5e5..890199e46 100644 --- a/packages/client/src/schema-component/antd/form-v2/Form.Designer.tsx +++ b/packages/client/src/schema-component/antd/form-v2/Form.Designer.tsx @@ -75,7 +75,8 @@ export const FormDesigner = () => { }); }} /> - + {/* */} + { const template = useSchemaTemplate(); return ( - + {/* */} + s; const RequestSchemaComponent: React.FC = (props) => { - const { onlyRenderProperties, hidden, scope, uid, components, onSuccess, schemaTransform = defaultTransform } = props; + const { + noForm, + onlyRenderProperties, + hidden, + scope, + uid, + components, + onSuccess, + schemaTransform = defaultTransform, + } = props; const { reset } = useSchemaComponentContext(); const conf = { url: `/uiSchemas:${onlyRenderProperties ? 'getProperties' : 'getJsonSchema'}/${uid}`, @@ -40,7 +50,9 @@ const RequestSchemaComponent: React.FC = (props) => if (hidden) { return ; } - return ( + return noForm ? ( + + ) : ( diff --git a/packages/client/src/schema-initializer/items/index.tsx b/packages/client/src/schema-initializer/items/index.tsx index 710b7dab3..9d3ca4a9b 100644 --- a/packages/client/src/schema-initializer/items/index.tsx +++ b/packages/client/src/schema-initializer/items/index.tsx @@ -60,7 +60,7 @@ export const ActionInitializer = (props) => { }; export const DataBlockInitializer = (props) => { - const { onCreateBlockSchema, componentType, createBlockSchema, insert, ...others } = props; + const { templateWrap, onCreateBlockSchema, componentType, createBlockSchema, insert, ...others } = props; const { getTemplateSchemaByMode } = useSchemaTemplateManager(); return ( { onClick={async ({ item }) => { if (item.template) { const s = await getTemplateSchemaByMode(item); - insert(s); + templateWrap ? insert(templateWrap(s, { item })) : insert(s); } else { if (onCreateBlockSchema) { onCreateBlockSchema({ item }); @@ -105,7 +105,17 @@ export const FormBlockInitializer = (props) => { } - componentType={'CreateForm'} + componentType={'FormItem'} + templateWrap={(templateSchema, { item }) => { + const s = createFormBlockSchema({ + template: templateSchema, + collection: item.name, + }); + if (item.template && item.mode === 'reference') { + s['x-template-key'] = item.template.key; + } + return s; + }} createBlockSchema={createFormBlockSchema} /> ); @@ -530,7 +540,20 @@ export const CreateFormBlockInitializer = (props) => { onClick={async ({ item }) => { if (item.template) { const s = await getTemplateSchemaByMode(item); - insert(s); + if (item.template.componentName === 'FormItem') { + const blockSchema = createFormBlockSchema({ + actionInitializers: 'CreateFormActionInitializers', + association, + collection: collection.name, + template: s, + }); + if (item.mode === 'reference') { + blockSchema['x-template-key'] = item.template.key; + } + insert(blockSchema); + } else { + insert(s); + } } else { insert( createFormBlockSchema({ @@ -541,7 +564,7 @@ export const CreateFormBlockInitializer = (props) => { ); } }} - items={useRecordCollectionDataSourceItems('CreateForm')} + items={useRecordCollectionDataSourceItems('FormItem')} /> ); }; @@ -558,7 +581,23 @@ export const RecordFormBlockInitializer = (props) => { onClick={async ({ item }) => { if (item.template) { const s = await getTemplateSchemaByMode(item); - insert(s); + if (item.template.componentName === 'FormItem') { + const blockSchema = createFormBlockSchema({ + association, + collection: collection.name, + action: 'get', + useSourceId: '{{ useSourceIdFromParentRecord }}', + useParams: '{{ useParamsFromRecord }}', + actionInitializers: 'UpdateFormActionInitializers', + template: s, + }); + if (item.mode === 'reference') { + blockSchema['x-template-key'] = item.template.key; + } + insert(blockSchema); + } else { + insert(s); + } } else { insert( createFormBlockSchema({ @@ -572,7 +611,7 @@ export const RecordFormBlockInitializer = (props) => { ); } }} - items={useRecordCollectionDataSourceItems('RecordForm')} + items={useRecordCollectionDataSourceItems('FormItem')} /> ); }; @@ -589,7 +628,22 @@ export const RecordReadPrettyFormBlockInitializer = (props) => { onClick={async ({ item }) => { if (item.template) { const s = await getTemplateSchemaByMode(item); - insert(s); + if (item.template.componentName === 'ReadPrettyFormItem') { + const blockSchema = createReadPrettyFormBlockSchema({ + association, + collection: collection.name, + action: 'get', + useSourceId: '{{ useSourceIdFromParentRecord }}', + useParams: '{{ useParamsFromRecord }}', + template: s, + }); + if (item.mode === 'reference') { + blockSchema['x-template-key'] = item.template.key; + } + insert(blockSchema); + } else { + insert(s); + } } else { insert( createReadPrettyFormBlockSchema({ @@ -602,7 +656,7 @@ export const RecordReadPrettyFormBlockInitializer = (props) => { ); } }} - items={useRecordCollectionDataSourceItems('ReadPrettyForm')} + items={useRecordCollectionDataSourceItems('ReadPrettyFormItem')} /> ); }; diff --git a/packages/client/src/schema-initializer/utils.ts b/packages/client/src/schema-initializer/utils.ts index 49e9365d2..e75076a8b 100644 --- a/packages/client/src/schema-initializer/utils.ts +++ b/packages/client/src/schema-initializer/utils.ts @@ -149,6 +149,7 @@ export const useCurrentSchema = (action: string, key: string, find = findSchema, }; export const useRecordCollectionDataSourceItems = (componentName) => { + const { t } = useTranslation(); const collection = useCollection(); const { getTemplatesByCollection } = useSchemaTemplateManager(); const templates = getTemplatesByCollection(collection.name).filter((template) => { @@ -173,12 +174,14 @@ export const useRecordCollectionDataSourceItems = (componentName) => { name: 'copy', title: '复制模板', children: templates.map((template) => { + const templateName = + template?.componentName === 'ReadPrettyFormItem' ? `${template?.name} ${t('(Fields only)')}` : template?.name; return { type: 'item', mode: 'copy', name: collection.name, template, - title: template.name || '未命名', + title: templateName || '未命名', }; }), }, @@ -188,12 +191,14 @@ export const useRecordCollectionDataSourceItems = (componentName) => { name: 'ref', title: '引用模板', children: templates.map((template) => { + const templateName = + template?.componentName === 'ReadPrettyFormItem' ? `${template?.name} ${t('(Fields only)')}` : template?.name; return { type: 'item', mode: 'reference', name: collection.name, template, - title: template.name || '未命名', + title: templateName || '未命名', }; }), }, @@ -242,12 +247,14 @@ export const useCollectionDataSourceItems = (componentName) => { name: 'copy', title: '复制模板', children: templates.map((template) => { + const templateName = + template?.componentName === 'FormItem' ? `${template?.name} ${t('(Fields only)')}` : template?.name; return { type: 'item', mode: 'copy', name: item.name, template, - title: template.name || '未命名', + title: templateName || '未命名', }; }), }, @@ -257,12 +264,14 @@ export const useCollectionDataSourceItems = (componentName) => { name: 'ref', title: '引用模板', children: templates.map((template) => { + const templateName = + template?.componentName === 'FormItem' ? `${template?.name} ${t('(Fields only)')}` : template?.name; return { type: 'item', mode: 'reference', name: item.name, template, - title: template.name || '未命名', + title: templateName || '未命名', }; }), }, @@ -281,6 +290,7 @@ export const createFormBlockSchema = (options) => { resource, association, action, + template, ...others } = options; const resourceName = resource || association || collection; @@ -310,7 +320,7 @@ export const createFormBlockSchema = (options) => { useProps: '{{ useFormBlockProps }}', }, properties: { - grid: { + grid: template || { type: 'void', 'x-component': 'Grid', 'x-initializer': formItemInitializers, @@ -343,6 +353,7 @@ export const createReadPrettyFormBlockSchema = (options) => { collection, association, resource, + template, ...others } = options; const resourceName = resource || association || collection; @@ -381,7 +392,7 @@ export const createReadPrettyFormBlockSchema = (options) => { }, properties: {}, }, - grid: { + grid: template || { type: 'void', 'x-component': 'Grid', 'x-initializer': formItemInitializers, diff --git a/packages/client/src/schema-settings/GeneralSchemaDesigner.tsx b/packages/client/src/schema-settings/GeneralSchemaDesigner.tsx index b0a56a7eb..5855dc9fb 100644 --- a/packages/client/src/schema-settings/GeneralSchemaDesigner.tsx +++ b/packages/client/src/schema-settings/GeneralSchemaDesigner.tsx @@ -4,6 +4,7 @@ import { useField, useFieldSchema } from '@formily/react'; import { Space } from 'antd'; import classNames from 'classnames'; import React from 'react'; +import { useTranslation } from 'react-i18next'; import { DragHandler, useCompile, useDesignable } from '../schema-component'; import { SchemaSettings } from './SchemaSettings'; @@ -33,6 +34,7 @@ export const GeneralSchemaDesigner = (props: any) => { const { title, template, draggable = true } = props; const { dn, designable } = useDesignable(); const field = useField(); + const { t } = useTranslation(); const fieldSchema = useFieldSchema(); const compile = useCompile(); const schemaSettingsProps = { @@ -43,13 +45,14 @@ export const GeneralSchemaDesigner = (props: any) => { if (!designable) { return null; } + const templateName = ['FormItem', 'ReadPrettyFormItem'].includes(template?.componentName) ? `${template?.name} ${t('(Fields only)')}` : template?.name; return (
{title && (
{compile(title)} - {template && 引用模板: {template?.name || '未命名'}} + {template && 引用模板: {templateName || '未命名'}}
)} diff --git a/packages/client/src/schema-settings/SchemaSettings.tsx b/packages/client/src/schema-settings/SchemaSettings.tsx index cc5dd51b4..bdb5a5196 100644 --- a/packages/client/src/schema-settings/SchemaSettings.tsx +++ b/packages/client/src/schema-settings/SchemaSettings.tsx @@ -67,9 +67,9 @@ interface SchemaSettingsProviderProps { export const SchemaSettingsProvider: React.FC = (props) => { const { children, fieldSchema, ...others } = props; - const { getTemplateBySchemaId } = useSchemaTemplateManager(); + const { getTemplateBySchema } = useSchemaTemplateManager(); const { name } = useCollection(); - const template = getTemplateBySchemaId(fieldSchema['x-uid']); + const template = getTemplateBySchema(fieldSchema); return ( {children} @@ -181,6 +181,147 @@ SchemaSettings.Template = (props) => { ); }; +const findGridSchema = (fieldSchema) => { + return fieldSchema.reduceProperties((buf, s) => { + if (s['x-component'] === 'FormV2') { + const f = s.reduceProperties((buf, s) => { + if (s['x-component'] === 'Grid') { + return s; + } + return buf; + }, null); + if (f) { + return f; + } + } + return buf; + }, null); +}; + +const findBlockTemplateSchema = (fieldSchema) => { + return fieldSchema.reduceProperties((buf, s) => { + if (s['x-component'] === 'FormV2') { + const f = s.reduceProperties((buf, s) => { + if (s['x-component'] === 'BlockTemplate') { + return s; + } + return buf; + }, null); + if (f) { + return f; + } + } + return buf; + }, null); +}; + +SchemaSettings.FormItemTemplate = (props) => { + const { insertAdjacentPosition = 'afterBegin', componentName, collectionName } = props; + const { t } = useTranslation(); + const { dn, setVisible, template, fieldSchema } = useSchemaSettings(); + const api = useAPIClient(); + const { saveAsTemplate, copyTemplateSchema } = useSchemaTemplateManager(); + if (!collectionName) { + return null; + } + if (template) { + return ( + { + const schema = await copyTemplateSchema(template); + const templateSchema = findBlockTemplateSchema(fieldSchema); + const sdn = createDesignable({ + api, + refresh: dn.refresh.bind(dn), + current: templateSchema.parent, + }); + sdn.loadAPIClientEvents(); + sdn.removeWithoutEmit(templateSchema); + sdn.insertAdjacent(insertAdjacentPosition, schema, { + async onSuccess() { + await api.request({ + url: `/uiSchemas:remove/${templateSchema['x-uid']}`, + }); + }, + }); + fieldSchema['x-template-key'] = null; + await api.request({ + url: `uiSchemas:patch`, + method: 'post', + data: { + 'x-uid': fieldSchema['x-uid'], + 'x-template-key': null, + }, + }); + dn.refresh(); + }} + > + {t('Convert reference to duplicate')} + + ); + } + return ( + { + setVisible(false); + const gridSchema = findGridSchema(fieldSchema); + console.log('gridSchema', gridSchema); + const values = await FormDialog('Save as template', () => { + return ( + + + + ); + }).open({}); + const sdn = createDesignable({ + api, + refresh: dn.refresh.bind(dn), + current: gridSchema.parent, + }); + sdn.loadAPIClientEvents(); + const { key } = await saveAsTemplate({ + collectionName, + componentName, + name: values.name, + uid: gridSchema['x-uid'], + }); + sdn.removeWithoutEmit(gridSchema); + sdn.insertAdjacent(insertAdjacentPosition, { + type: 'void', + 'x-component': 'BlockTemplate', + 'x-component-props': { + templateId: key, + }, + }); + fieldSchema['x-template-key'] = key; + await api.request({ + url: `uiSchemas:patch`, + method: 'post', + data: { + 'x-uid': fieldSchema['x-uid'], + 'x-template-key': key, + }, + }); + }} + > + {t('Save as template')} + + ); +}; + SchemaSettings.Item = (props) => { let { eventKey } = props; return ( diff --git a/packages/client/src/schema-templates/BlockTemplate.tsx b/packages/client/src/schema-templates/BlockTemplate.tsx index cbf154932..c98e67355 100644 --- a/packages/client/src/schema-templates/BlockTemplate.tsx +++ b/packages/client/src/schema-templates/BlockTemplate.tsx @@ -19,7 +19,7 @@ export const BlockTemplate = observer((props: any) => { return (
- +
); diff --git a/packages/client/src/schema-templates/SchemaTemplateManagerProvider.tsx b/packages/client/src/schema-templates/SchemaTemplateManagerProvider.tsx index 0cf7772d0..6b4c990af 100644 --- a/packages/client/src/schema-templates/SchemaTemplateManagerProvider.tsx +++ b/packages/client/src/schema-templates/SchemaTemplateManagerProvider.tsx @@ -46,10 +46,12 @@ const regenerateUid = (s: ISchema) => { }; export const useSchemaTemplate = () => { - const { getTemplateBySchemaId } = useSchemaTemplateManager(); + const { getTemplateBySchema, templates } = useSchemaTemplateManager(); const fieldSchema = useFieldSchema(); const schemaId = fieldSchema['x-uid']; - return useMemo(() => getTemplateBySchemaId(schemaId), [schemaId]); + const templateKey = fieldSchema['x-template-key']; + console.log('templateKey', { schemaId, templateKey }) + return useMemo(() => getTemplateBySchema(fieldSchema), [schemaId, templateKey]); }; export const useSchemaTemplateManager = () => { @@ -98,7 +100,20 @@ export const useSchemaTemplateManager = () => { await refresh(); return { key }; }, + getTemplateBySchema(schema) { + const templateKey = schema['x-template-key']; + if (templateKey) { + return templates?.find((template) => template.key === templateKey); + } + const schemaId = schema['x-uid']; + if (schemaId) { + return templates?.find((template) => template.uid === schemaId); + } + }, getTemplateBySchemaId(schemaId) { + if (!schemaId) { + return null; + } return templates?.find((template) => template.uid === schemaId); }, getTemplateById(key) {