diff --git a/packages/client/src/collection-manager/ResourceActionProvider.tsx b/packages/client/src/collection-manager/ResourceActionProvider.tsx index 6f610c4b1..c443e5dcb 100644 --- a/packages/client/src/collection-manager/ResourceActionProvider.tsx +++ b/packages/client/src/collection-manager/ResourceActionProvider.tsx @@ -18,10 +18,17 @@ const ResourceContext = createContext(null); const CollectionResourceActionProvider = (props) => { let { collection, request, uid } = props; const api = useAPIClient(); + const record = useRecord(); + const actionName = request?.action; + const others = {}; + if (actionName === 'get') { + others['filterByTk'] = record[collection.targetKey || collection.filterTargetKey || 'id']; + } const service = useRequest( { ...request, params: { + ...others, ...request?.params, appends: collection.fields.filter((field) => field.target).map((field) => field.name), }, diff --git a/packages/client/src/collection-manager/action-hooks.ts b/packages/client/src/collection-manager/action-hooks.ts index 9e349f338..6bbce4716 100644 --- a/packages/client/src/collection-manager/action-hooks.ts +++ b/packages/client/src/collection-manager/action-hooks.ts @@ -1,4 +1,5 @@ import { useForm } from '@formily/react'; +import { message } from 'antd'; import { useCollection, useCollectionManager } from '.'; import { useRequest } from '../api-client'; import { useRecord } from '../record-provider'; @@ -121,6 +122,22 @@ export const useCreateActionWithoutRefresh = () => { }; }; +export const useUpdateViewAction = () => { + const form = useForm(); + const ctx = useActionContext(); + // const { refresh } = useResourceActionContext(); + const { resource, targetKey } = useResourceContext(); + const { [targetKey]: filterByTk } = useRecord(); + return { + async run() { + await form.submit(); + await resource.update({ filterByTk, values: form.values }); + // refresh(); + message.success('保存成功'); + }, + }; +} + export const useUpdateAction = () => { const form = useForm(); const ctx = useActionContext(); @@ -172,6 +189,14 @@ export const useValuesFromRecord = (options) => { }); }; +export const useValuesFromRA = (options) => { + const ctx = useResourceActionContext(); + return useRequest(() => Promise.resolve(ctx.data), { + ...options, + refreshDeps: [ctx.data], + }); +}; + export const useCreateActionAndRefreshCM = () => { const { run } = useCreateAction(); const { refreshCM } = useCollectionManager(); diff --git a/packages/client/src/schema-component/antd/record-picker/RecordPicker.tsx b/packages/client/src/schema-component/antd/record-picker/RecordPicker.tsx index d053ea13b..5c14bae16 100644 --- a/packages/client/src/schema-component/antd/record-picker/RecordPicker.tsx +++ b/packages/client/src/schema-component/antd/record-picker/RecordPicker.tsx @@ -16,6 +16,8 @@ import { toArr } from '@formily/shared'; import { Button, Drawer, Select, Space } from 'antd'; import React, { createContext, useContext, useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; +import { useCollectionField } from '../../../collection-manager'; +import { RecordProvider } from '../../../record-provider'; import { useAttach } from '../../hooks/useAttach'; import { ActionContext, useActionContext } from '../action'; @@ -191,12 +193,15 @@ RecordPicker.SelectedItem = () => { const fieldSchema = useFieldSchema(); const [visible, setVisible] = useState(false); const fieldNames = ctx.field.componentProps.fieldNames; + const { target } = useCollectionField(); return ( setVisible(true)}> {ctx.record[fieldNames?.label || 'id']} - + + + ); }; diff --git a/packages/client/src/schema-initializer/Initializers/Items/LinkToCollectionFieldInitializer.tsx b/packages/client/src/schema-initializer/Initializers/Items/LinkToCollectionFieldInitializer.tsx index 47312aafa..0f621a0ea 100644 --- a/packages/client/src/schema-initializer/Initializers/Items/LinkToCollectionFieldInitializer.tsx +++ b/packages/client/src/schema-initializer/Initializers/Items/LinkToCollectionFieldInitializer.tsx @@ -1,3 +1,4 @@ +import { ISchema } from '@formily/react'; import { Switch } from 'antd'; import React from 'react'; import { SchemaInitializer } from '../../SchemaInitializer'; @@ -113,6 +114,10 @@ export const LinkToFieldInitializer = (props) => { 'x-component': 'RecordPicker.SelectedItem', properties: { drawer1: { + 'x-decorator': 'CollectionProvider', + 'x-decorator-props': { + name: item.field.target, + }, 'x-component': 'Action.Drawer', 'x-component-props': { className: 'nb-action-popup', @@ -148,7 +153,7 @@ export const LinkToFieldInitializer = (props) => { }, }, }, - }); + } as ISchema); }} >
diff --git a/packages/client/src/schema-initializer/Initializers/Items/RecordDetailsBlockInitializer.tsx b/packages/client/src/schema-initializer/Initializers/Items/RecordDetailsBlockInitializer.tsx new file mode 100644 index 000000000..b817db1e3 --- /dev/null +++ b/packages/client/src/schema-initializer/Initializers/Items/RecordDetailsBlockInitializer.tsx @@ -0,0 +1,68 @@ +import { FormOutlined } from '@ant-design/icons'; +import { ISchema } from '@formily/react'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { SchemaInitializer } from '../..'; +import { useCollection } from '../../../collection-manager'; + +const createSchema = (collectionName) => { + const schema: ISchema = { + type: 'void', + 'x-decorator': 'ResourceActionProvider', + 'x-decorator-props': { + collection: collectionName, + request: { + resource: collectionName, + action: 'get', + params: {}, + }, + }, + 'x-designer': 'Form.Designer', + 'x-component': 'CardItem', + properties: { + form: { + type: 'void', + 'x-decorator': 'Form', + 'x-decorator-props': { + useValues: '{{ cm.useValuesFromRA }}', + }, + properties: { + actions: { + type: 'void', + 'x-initializer': 'RecordDetailsActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 24, + }, + }, + properties: {}, + }, + grid: { + type: 'void', + 'x-component': 'Grid', + 'x-read-pretty': true, + 'x-initializer': 'GridFormItemInitializers', + properties: {}, + }, + }, + }, + }, + }; + return schema; +}; + +export const RecordDetailsBlockInitializer = (props) => { + const { insert } = props; + const { name } = useCollection(); + const { t } = useTranslation(); + return ( + } + onClick={({ item }) => { + insert(createSchema(name)); + }} + /> + ); +}; diff --git a/packages/client/src/schema-initializer/Initializers/Items/RecordFormBlockInitializer.tsx b/packages/client/src/schema-initializer/Initializers/Items/RecordFormBlockInitializer.tsx index 578b6d0ef..9173e4efd 100644 --- a/packages/client/src/schema-initializer/Initializers/Items/RecordFormBlockInitializer.tsx +++ b/packages/client/src/schema-initializer/Initializers/Items/RecordFormBlockInitializer.tsx @@ -23,7 +23,9 @@ const createSchema = (collectionName) => { form: { type: 'void', 'x-decorator': 'Form', - 'x-decorator-props': {}, + 'x-decorator-props': { + useValues: '{{ cm.useValuesFromRA }}', + }, properties: { grid: { type: 'void', @@ -33,7 +35,7 @@ const createSchema = (collectionName) => { }, actions: { type: 'void', - 'x-initializer': 'FormActionInitializers', + 'x-initializer': 'RecordFormActionInitializers', 'x-component': 'ActionBar', 'x-component-props': { layout: 'one-column', @@ -41,7 +43,17 @@ const createSchema = (collectionName) => { marginTop: 24, }, }, - properties: {}, + properties: { + submit: { + title: '{{ t("Submit") }}', + 'x-action': 'submit', + 'x-component': 'Action', + 'x-component-props': { + type: 'primary', + useAction: '{{ cm.useUpdateViewAction }}', + }, + }, + }, }, }, }, diff --git a/packages/client/src/schema-initializer/Initializers/Items/index.ts b/packages/client/src/schema-initializer/Initializers/Items/index.ts index 0d7b4b4d4..f5aa32677 100644 --- a/packages/client/src/schema-initializer/Initializers/Items/index.ts +++ b/packages/client/src/schema-initializer/Initializers/Items/index.ts @@ -7,6 +7,7 @@ export * from './FormBlockInitializer'; export * from './GeneralInitializer'; export * from './LinkToCollectionFieldInitializer'; export * from './MarkdownBlockInitializer'; +export * from './RecordDetailsBlockInitializer'; export * from './RecordFormBlockInitializer'; export * from './RecordRelationBlockInitializer'; export * from './SubTableFieldInitializer'; diff --git a/packages/client/src/schema-initializer/Initializers/RecordBlockInitializers.tsx b/packages/client/src/schema-initializer/Initializers/RecordBlockInitializers.tsx index 0e164326c..d575ebae5 100644 --- a/packages/client/src/schema-initializer/Initializers/RecordBlockInitializers.tsx +++ b/packages/client/src/schema-initializer/Initializers/RecordBlockInitializers.tsx @@ -36,7 +36,7 @@ export const RecordBlockInitializers = (props: any) => { { type: 'item', title: 'Details', - component: 'RecordFormBlockInitializer', + component: 'RecordDetailsBlockInitializer', }, { type: 'item', diff --git a/packages/client/src/schema-initializer/Initializers/RecordDetailsActionInitializers.tsx b/packages/client/src/schema-initializer/Initializers/RecordDetailsActionInitializers.tsx new file mode 100644 index 000000000..70a13d016 --- /dev/null +++ b/packages/client/src/schema-initializer/Initializers/RecordDetailsActionInitializers.tsx @@ -0,0 +1,81 @@ +// 普通表单的操作配置 +export const RecordDetailsActionInitializers = { + style: { + marginLeft: 8, + }, + title: '{{t("Configure actions")}}', + items: [ + { + type: 'itemGroup', + title: '{{t("Enable actions")}}', + children: [ + { + type: 'item', + title: '{{t("Edit")}}', + component: 'ActionInitializer', + schema: { + title: '{{t("Edit")}}', + type: 'void', + 'x-action': 'update', + 'x-designer': 'Action.Designer', + 'x-component': 'Action', + 'x-component-props': { + type: 'primary', + }, + properties: { + drawer: { + type: 'void', + 'x-decorator': 'Form', + 'x-decorator-props': { + useValues: '{{ cm.useValuesFromRA }}', + }, + 'x-component': 'Action.Drawer', + title: '{{ t("Edit record") }}', + properties: { + grid: { + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'GridFormItemInitializers', + properties: {}, + }, + footer: { + type: 'void', + 'x-component': 'Action.Drawer.Footer', + properties: { + actions: { + type: 'void', + 'x-component': 'ActionBar', + 'x-component-props': { + layout: 'one-column', + }, + properties: { + cancel: { + title: '{{ t("Cancel") }}', + 'x-action': 'cancel', + 'x-component': 'Action', + 'x-component-props': { + useAction: '{{ cm.useCancelAction }}', + }, + }, + submit: { + title: '{{ t("Submit") }}', + 'x-action': 'submit', + 'x-component': 'Action', + 'x-component-props': { + type: 'primary', + useAction: '{{ cm.useUpdateAction }}', + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + ], + }, + ], +}; diff --git a/packages/client/src/schema-initializer/Initializers/RecordFormActionInitializers.tsx b/packages/client/src/schema-initializer/Initializers/RecordFormActionInitializers.tsx new file mode 100644 index 000000000..0aabeb1e0 --- /dev/null +++ b/packages/client/src/schema-initializer/Initializers/RecordFormActionInitializers.tsx @@ -0,0 +1,27 @@ +// 普通表单的操作配置 +export const RecordFormActionInitializers = { + title: '{{t("Configure actions")}}', + items: [ + { + type: 'itemGroup', + title: '{{t("Enable actions")}}', + children: [ + { + type: 'item', + title: '{{t("Submit")}}', + component: 'ActionInitializer', + schema: { + title: '{{t("Submit")}}', + 'x-action': 'submit', + 'x-align': 'left', + 'x-component': 'Action', + 'x-component-props': { + type: 'primary', + useAction: '{{ cm.useUpdateViewAction }}', + }, + }, + }, + ], + }, + ], +}; diff --git a/packages/client/src/schema-initializer/Initializers/index.tsx b/packages/client/src/schema-initializer/Initializers/index.tsx index 3c1a26714..6b3c7e380 100644 --- a/packages/client/src/schema-initializer/Initializers/index.tsx +++ b/packages/client/src/schema-initializer/Initializers/index.tsx @@ -6,6 +6,8 @@ import { GridFormItemInitializers } from './GridFormItemInitializers'; import * as Items from './Items'; import { PopupFormActionInitializers } from './PopupFormActionInitializers'; import { RecordBlockInitializers } from './RecordBlockInitializers'; +import { RecordDetailsActionInitializers } from './RecordDetailsActionInitializers'; +import { RecordFormActionInitializers } from './RecordFormActionInitializers'; import { TableActionInitializers } from './TableActionInitializers'; import { TableColumnInitializers } from './TableColumnInitializers'; import { TableFieldRecordActionInitializers } from './TableFieldRecordActionInitializers'; @@ -39,4 +41,8 @@ export const initializes = { TableFieldRecordActionInitializers, // 添加标签页 TabPaneInitializers, + + RecordDetailsActionInitializers, + + RecordFormActionInitializers, }; diff --git a/packages/database/src/collection.ts b/packages/database/src/collection.ts index ebc6169bd..922591d5b 100644 --- a/packages/database/src/collection.ts +++ b/packages/database/src/collection.ts @@ -67,7 +67,7 @@ export class Collection< private sequelizeModelOptions() { const { name, tableName } = this.options; return { - ..._.omit(this.options, ['name', 'fields', 'model']), + ..._.omit(this.options, ['name', 'fields', 'model', 'targetKey']), modelName: name, sequelize: this.context.database.sequelize, tableName: tableName || name, diff --git a/packages/plugin-acl/src/collections/roles.ts b/packages/plugin-acl/src/collections/roles.ts index 5adf61ce3..22f1330c7 100644 --- a/packages/plugin-acl/src/collections/roles.ts +++ b/packages/plugin-acl/src/collections/roles.ts @@ -5,6 +5,8 @@ export default { title: '{{t("Roles")}}', autoGenId: false, model: 'RoleModel', + filterTargetKey: 'name', + // targetKey: 'name', fields: [ { type: 'uid',