fix: 数据关联表引用自己的情况不显示内容-同步官方, 发布后需要重新配置区块
This commit is contained in:
parent
93b7abbd30
commit
2544dab6be
@ -5,12 +5,19 @@ import {
|
||||
useCollectionParentRecordData,
|
||||
useCollectionRecordData,
|
||||
} from '../..';
|
||||
import { useSourceKey } from '../../modules/blocks/useSourceKey';
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated
|
||||
* 已弃用(该方法现在只是用来兼容旧版 Schema 的),请通过各个区块的 x-use-decorator-props 中获取 sourceId
|
||||
*
|
||||
* 注意:这里有一个需要更改 schema 才能解决的问题,就是在获取 sourceId 的时候无法确定(在关系字段和当前表同表时)
|
||||
* 是需要从 recordData 还是 parentRecordData 中获取;解决方法是通过更改 schema,在不同类型的关系区块中
|
||||
* (`通过点击关系字段按钮打开的弹窗中创建的非关系字段区块`和`关系字段区块`)使用不同的 hook。
|
||||
*
|
||||
* 更新:上面所说的“需要更改 schema 才能解决的问题”已在这个任务中更改:https://nocobase.height.app/T-3848/description
|
||||
*
|
||||
* @param param0
|
||||
* @returns
|
||||
*/
|
||||
@ -18,26 +25,19 @@ export const useDataBlockSourceId = ({ association }: { association: string }) =
|
||||
const recordData = useCollectionRecordData();
|
||||
const parentRecordData = useCollectionParentRecordData();
|
||||
const cm = useCollectionManager();
|
||||
const collectionOutsideBlock = useCollection<InheritanceCollectionMixin>();
|
||||
const currentRecordCollection = useCollection<InheritanceCollectionMixin>();
|
||||
const sourceKey = useSourceKey(association);
|
||||
|
||||
if (!association) return;
|
||||
|
||||
const associationField = cm.getCollectionField(association);
|
||||
const associationCollection = cm.getCollection<InheritanceCollectionMixin>(associationField.collectionName);
|
||||
const sourceCollection = cm.getCollection<InheritanceCollectionMixin>(association.split('.')[0]);
|
||||
|
||||
if (
|
||||
collectionOutsideBlock.name === associationCollection.name ||
|
||||
collectionOutsideBlock.getParentCollectionsName?.().includes(associationCollection.name)
|
||||
currentRecordCollection.name === sourceCollection.name ||
|
||||
currentRecordCollection.getParentCollectionsName?.().includes(sourceCollection.name)
|
||||
) {
|
||||
return recordData?.[
|
||||
associationField.sourceKey ||
|
||||
associationCollection.filterTargetKey ||
|
||||
associationCollection.getPrimaryKey() ||
|
||||
'id'
|
||||
];
|
||||
return recordData?.[sourceKey];
|
||||
}
|
||||
|
||||
return parentRecordData?.[
|
||||
associationField.sourceKey || associationCollection.filterTargetKey || associationCollection.getPrimaryKey() || 'id'
|
||||
];
|
||||
return parentRecordData?.[sourceKey];
|
||||
};
|
||||
|
@ -7,6 +7,7 @@ import { AllDataBlockProps, useDataBlockProps } from './DataBlockProvider';
|
||||
import { useDataBlockResource } from './DataBlockResourceProvider';
|
||||
import { useDataSourceHeaders } from '../utils';
|
||||
import { useDataLoadingMode } from '../../modules/blocks/data-blocks/details-multi/setDataLoadingModeSettingsItem';
|
||||
import { useSourceKey } from '../../modules/blocks/useSourceKey';
|
||||
|
||||
export const BlockRequestContext = createContext<UseRequestResult<any>>(null);
|
||||
BlockRequestContext.displayName = 'BlockRequestContext';
|
||||
@ -57,14 +58,15 @@ function useParentRequest<T>(options: Omit<AllDataBlockProps, 'type'>) {
|
||||
const api = useAPIClient();
|
||||
const dataBlockProps = useDataBlockProps();
|
||||
const headers = useDataSourceHeaders(dataBlockProps.dataSource);
|
||||
const sourceKey = useSourceKey(association);
|
||||
return useRequest<T>(
|
||||
async () => {
|
||||
if (parentRecord) return Promise.resolve({ data: parentRecord });
|
||||
if (!association) return Promise.resolve({ data: undefined });
|
||||
if (!association || !sourceKey) return Promise.resolve({ data: undefined });
|
||||
// "association": "Collection.Field"
|
||||
const arr = association.split('.');
|
||||
// <collection>:get/<filterByTk>
|
||||
const url = `${arr[0]}:get/${sourceId}`;
|
||||
const url = `${arr[0]}:get?filter[${sourceKey}]=${sourceId}`;
|
||||
const res = await api.request({ url, headers });
|
||||
return res.data;
|
||||
},
|
||||
|
@ -61,6 +61,7 @@ export * from './modules/blocks/data-blocks/table';
|
||||
export * from './modules/blocks/data-blocks/form';
|
||||
export * from './modules/blocks/data-blocks/table-selector';
|
||||
export * from './modules/blocks/data-blocks/details-multi/setDataLoadingModeSettingsItem';
|
||||
export * from './modules/blocks/useSourceIdCommon';
|
||||
|
||||
export * as __UNSAFE__ from './unsafe';
|
||||
export type {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useDataBlockSourceId } from '../../../../../block-provider/hooks/useDataBlockSourceId';
|
||||
import { useSourceIdCommon } from '../../../useSourceIdCommon';
|
||||
|
||||
export function useDetailsWithPaginationDecoratorProps(props) {
|
||||
let sourceId;
|
||||
@ -6,7 +6,7 @@ export function useDetailsWithPaginationDecoratorProps(props) {
|
||||
// association 的值是固定不变的,所以可以在条件中使用 hooks
|
||||
if (props.association) {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
sourceId = useDataBlockSourceId({ association: props.association });
|
||||
sourceId = useSourceIdCommon(props.association);
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -69,6 +69,7 @@ export function useCreateSingleDetailsSchema() {
|
||||
? {
|
||||
association,
|
||||
dataSource: item.dataSource,
|
||||
isCurrent: true,
|
||||
}
|
||||
: {
|
||||
collectionName: item.collectionName || item.name,
|
||||
|
@ -6,9 +6,14 @@ export function createDetailsUISchema(options: {
|
||||
collectionName?: string;
|
||||
association?: string;
|
||||
templateSchema?: ISchema;
|
||||
/**
|
||||
* 如果为 true,则表示当前创建的区块 record 就是 useRecord 返回的 record
|
||||
*/
|
||||
isCurrent?: boolean;
|
||||
}): ISchema {
|
||||
const { collectionName, dataSource, association, templateSchema } = options;
|
||||
const resourceName = association || collectionName;
|
||||
const isCurrentObj = options.isCurrent ? { 'x-is-current': true } : {};
|
||||
|
||||
if (!dataSource) {
|
||||
throw new Error('dataSource are required');
|
||||
@ -29,6 +34,7 @@ export function createDetailsUISchema(options: {
|
||||
'x-toolbar': 'BlockSchemaToolbar',
|
||||
'x-settings': 'blockSettings:details',
|
||||
'x-component': 'CardItem',
|
||||
...isCurrentObj,
|
||||
properties: {
|
||||
[uid()]: {
|
||||
type: 'void',
|
||||
|
@ -1,6 +1,16 @@
|
||||
import { useFieldSchema } from '@formily/react';
|
||||
import { useParamsFromRecord } from '../../../../../block-provider/BlockProvider';
|
||||
import { useDataBlockSourceId } from '../../../../../block-provider/hooks/useDataBlockSourceId';
|
||||
import {
|
||||
useCollectionParentRecordData,
|
||||
useCollectionRecordData,
|
||||
} from '../../../../../data-source/collection-record/CollectionRecordProvider';
|
||||
import { useSourceKey } from '../../../useSourceKey';
|
||||
|
||||
/**
|
||||
* 应用在通过 Current record 选项创建的区块中(弹窗中的 Add block 菜单)
|
||||
* @param props
|
||||
* @returns
|
||||
*/
|
||||
export function useDetailsDecoratorProps(props) {
|
||||
const params = useParamsFromRecord();
|
||||
let sourceId;
|
||||
@ -8,7 +18,7 @@ export function useDetailsDecoratorProps(props) {
|
||||
// association 的值是固定不变的,所以可以在条件中使用 hooks
|
||||
if (props.association) {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
sourceId = useDataBlockSourceId({ association: props.association });
|
||||
sourceId = useDetailsSourceId(props.association);
|
||||
}
|
||||
|
||||
return {
|
||||
@ -16,3 +26,18 @@ export function useDetailsDecoratorProps(props) {
|
||||
sourceId,
|
||||
};
|
||||
}
|
||||
|
||||
export function useDetailsSourceId(association: string) {
|
||||
const fieldSchema = useFieldSchema();
|
||||
const recordData = useCollectionRecordData();
|
||||
const parentRecordData = useCollectionParentRecordData();
|
||||
const sourceKey = useSourceKey(association);
|
||||
|
||||
if (!association) return;
|
||||
|
||||
if (fieldSchema['x-is-current']) {
|
||||
return parentRecordData?.[sourceKey];
|
||||
}
|
||||
|
||||
return recordData?.[sourceKey];
|
||||
}
|
||||
|
@ -49,6 +49,7 @@ export function useCreateEditFormBlock() {
|
||||
? {
|
||||
association,
|
||||
dataSource: item.dataSource,
|
||||
isCurrent: true,
|
||||
}
|
||||
: {
|
||||
collectionName: item.collectionName || item.name,
|
||||
|
@ -7,11 +7,16 @@ interface EditFormBlockOptions {
|
||||
collectionName?: string;
|
||||
association?: string;
|
||||
templateSchema?: ISchema;
|
||||
/**
|
||||
* 如果为 true,则表示当前创建的区块 record 就是 useRecord 返回的 record
|
||||
*/
|
||||
isCurrent?: boolean;
|
||||
}
|
||||
|
||||
export function createEditFormBlockUISchema(options: EditFormBlockOptions): ISchema {
|
||||
const { collectionName, dataSource, association, templateSchema } = options;
|
||||
const resourceName = association || collectionName;
|
||||
const isCurrentObj = options.isCurrent ? { 'x-is-current': true } : {};
|
||||
|
||||
if (!dataSource) {
|
||||
throw new Error('dataSource are required');
|
||||
@ -34,6 +39,7 @@ export function createEditFormBlockUISchema(options: EditFormBlockOptions): ISch
|
||||
'x-toolbar': 'BlockSchemaToolbar',
|
||||
'x-settings': 'blockSettings:editForm',
|
||||
'x-component': 'CardItem',
|
||||
...isCurrentObj,
|
||||
properties: {
|
||||
[uid()]: {
|
||||
type: 'void',
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useFormBlockSourceId } from './useFormBlockSourceId';
|
||||
import { useSourceIdCommon } from '../../../useSourceIdCommon';
|
||||
|
||||
export function useCreateFormBlockDecoratorProps(props) {
|
||||
let sourceId;
|
||||
@ -6,7 +6,7 @@ export function useCreateFormBlockDecoratorProps(props) {
|
||||
// association 的值是固定不变的,所以这里可以使用 hooks
|
||||
if (props.association) {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
sourceId = useFormBlockSourceId(props);
|
||||
sourceId = useSourceIdCommon(props.association);
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { useParamsFromRecord } from '../../../../../block-provider/BlockProvider';
|
||||
import { useFormBlockSourceId } from './useFormBlockSourceId';
|
||||
import { useDetailsSourceId } from '../../details-single/hooks/useDetailsDecoratorProps';
|
||||
|
||||
export function useEditFormBlockDecoratorProps(props) {
|
||||
const params = useFormBlockParams();
|
||||
@ -7,8 +7,9 @@ export function useEditFormBlockDecoratorProps(props) {
|
||||
|
||||
// association 的值是固定不变的,所以这里可以使用 hooks
|
||||
if (props.association) {
|
||||
// 复用详情区块的 sourceId 获取逻辑
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
sourceId = useFormBlockSourceId(props);
|
||||
sourceId = useDetailsSourceId(props.association);
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -1,5 +0,0 @@
|
||||
import { useDataBlockSourceId } from '../../../../../block-provider/hooks/useDataBlockSourceId';
|
||||
|
||||
export function useFormBlockSourceId(props) {
|
||||
return useDataBlockSourceId(props);
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import { useDataBlockSourceId } from '../../../../../block-provider/hooks/useDataBlockSourceId';
|
||||
import { useGridCardBlockParams } from './useGridCardBlockParams';
|
||||
import { useSourceIdCommon } from '../../../useSourceIdCommon';
|
||||
|
||||
export function useGridCardBlockDecoratorProps(props) {
|
||||
const params = useGridCardBlockParams(props);
|
||||
@ -8,7 +8,7 @@ export function useGridCardBlockDecoratorProps(props) {
|
||||
// 因为 association 是固定的,所以可以在条件中使用 hooks
|
||||
if (props.association) {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
sourceId = useDataBlockSourceId({ association: props.association });
|
||||
sourceId = useSourceIdCommon(props.association);
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useDataBlockSourceId } from '../../../../../block-provider/hooks/useDataBlockSourceId';
|
||||
import { useSourceIdCommon } from '../../../useSourceIdCommon';
|
||||
|
||||
export function useListBlockDecoratorProps(props) {
|
||||
let sourceId;
|
||||
@ -6,7 +6,7 @@ export function useListBlockDecoratorProps(props) {
|
||||
// 因为 association 的值是固定的,所以这里可以使用 hooks
|
||||
if (props.association) {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
sourceId = useDataBlockSourceId({ association: props.association });
|
||||
sourceId = useSourceIdCommon(props.association);
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { useFieldSchema } from '@nocobase/schema';
|
||||
import { useParsedFilter } from '../../../../../block-provider/hooks/useParsedFilter';
|
||||
import { useMemo } from 'react';
|
||||
import { useDataBlockSourceId } from '../../../../../block-provider/hooks/useDataBlockSourceId';
|
||||
import { useSourceIdCommon } from '../../../useSourceIdCommon';
|
||||
|
||||
export const useTableBlockDecoratorProps = (props) => {
|
||||
const params = useTableBlockParams(props);
|
||||
@ -44,7 +44,7 @@ function useTableBlockSourceId(props) {
|
||||
// 因为 association 是固定不变的,所以在条件中使用 hooks 是安全的
|
||||
if (props.association) {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
sourceId = useDataBlockSourceId({ association: props.association });
|
||||
sourceId = useSourceIdCommon(props.association);
|
||||
}
|
||||
|
||||
return sourceId;
|
||||
|
17
packages/core/client/src/modules/blocks/useSourceIdCommon.ts
Normal file
17
packages/core/client/src/modules/blocks/useSourceIdCommon.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { useCollectionRecordData } from '../../data-source/collection-record/CollectionRecordProvider';
|
||||
import { useSourceKey } from './useSourceKey';
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* 大部分区块(除了详情和编辑表单)都适用的获取 sourceId 的 hook
|
||||
* @param association
|
||||
* @returns
|
||||
*/
|
||||
export const useSourceIdCommon = (association: string) => {
|
||||
const recordData = useCollectionRecordData();
|
||||
const sourceKey = useSourceKey(association);
|
||||
|
||||
if (!association) return;
|
||||
|
||||
return recordData?.[sourceKey];
|
||||
};
|
26
packages/core/client/src/modules/blocks/useSourceKey.ts
Normal file
26
packages/core/client/src/modules/blocks/useSourceKey.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { InheritanceCollectionMixin } from '../../collection-manager/mixins/InheritanceCollectionMixin';
|
||||
import { useCollectionManager } from '../../data-source/collection/CollectionManagerProvider';
|
||||
|
||||
/**
|
||||
* 用于获取关系字段的 source collection 的 key
|
||||
* @param association string
|
||||
* @returns
|
||||
*/
|
||||
export const useSourceKey = (association: string) => {
|
||||
const cm = useCollectionManager();
|
||||
|
||||
if (!association) return;
|
||||
|
||||
const associationField = cm.getCollectionField(association);
|
||||
|
||||
if (!associationField) {
|
||||
return;
|
||||
}
|
||||
|
||||
const sourceCollection = cm.getCollection<InheritanceCollectionMixin>(association.split('.')[0]);
|
||||
|
||||
// 1. hasOne 和 hasMany 和 belongsToMany 的字段存在 sourceKey,所以会直接返回 sourceKey;
|
||||
// 2. belongsTo 不存在 sourceKey,所以会使用 filterTargetKey;
|
||||
// 3. 后面的主键和 id 是为了保险起见加上的;
|
||||
return associationField.sourceKey || sourceCollection.filterTargetKey || sourceCollection.getPrimaryKey() || 'id';
|
||||
};
|
@ -1,4 +1,4 @@
|
||||
import { useDataBlockSourceId } from '@nocobase/client';
|
||||
import { useSourceIdCommon } from '@nocobase/client';
|
||||
import { useCalendarBlockParams } from './useCalendarBlockParams';
|
||||
|
||||
export function useCalendarBlockDecoratorProps(props) {
|
||||
@ -8,7 +8,7 @@ export function useCalendarBlockDecoratorProps(props) {
|
||||
// 因为 association 是一个固定的值,所以可以在 hooks 中直接使用
|
||||
if (props.association) {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
sourceId = useDataBlockSourceId({ association: props.association });
|
||||
sourceId = useSourceIdCommon(props.association);
|
||||
}
|
||||
|
||||
return {
|
||||
|
Loading…
Reference in New Issue
Block a user