mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-07-01 18:52:20 +08:00
fix: issue when adding a one-to-one relationship field in the form (#5975)
This commit is contained in:
parent
3ed00a2ebf
commit
81ada5022a
@ -9,7 +9,7 @@
|
||||
|
||||
import { uid } from '@formily/shared';
|
||||
import { Divider, Empty, Input, MenuProps } from 'antd';
|
||||
import React, { useEffect, useMemo, useState, useRef } from 'react';
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useCompile } from '../../../';
|
||||
|
||||
@ -36,10 +36,11 @@ export const SearchFields = ({ value: outValue, onChange, name }) => {
|
||||
useEffect(() => {
|
||||
const focusInput = () => {
|
||||
if (
|
||||
inputRef.current &&
|
||||
document.activeElement?.id !== inputRef.current.input.id &&
|
||||
getPrefixAndCompare(document.activeElement?.id, inputRef.current.input.id)
|
||||
) {
|
||||
inputRef.current?.focus();
|
||||
inputRef.current.focus();
|
||||
}
|
||||
};
|
||||
|
||||
@ -96,20 +97,18 @@ export const SearchFields = ({ value: outValue, onChange, name }) => {
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
let currentName = null;
|
||||
export const useMenuSearch = (props: { children: any[]; showType?: boolean; hideSearch?: boolean; name?: string }) => {
|
||||
const { children, showType, hideSearch, name } = props;
|
||||
const items = children?.concat?.() || [];
|
||||
const [searchValue, setSearchValue] = useState(null);
|
||||
const compile = useCompile();
|
||||
|
||||
const [searchValue, setSearchValue] = useState(null);
|
||||
// 处理搜索逻辑
|
||||
const limitedSearchedItems = useMemo(() => {
|
||||
if (!searchValue || searchValue === '') {
|
||||
return items;
|
||||
const filteredItems = (data, name) => {
|
||||
if (!searchValue || searchValue === '' || (currentName && currentName !== name)) {
|
||||
return data;
|
||||
}
|
||||
const lowerSearchValue = searchValue.toLocaleLowerCase();
|
||||
return items.filter((item) => {
|
||||
return data.filter((item) => {
|
||||
return (
|
||||
(item.title || item.label) &&
|
||||
String(compile(item.title || item.label))
|
||||
@ -117,64 +116,72 @@ export const useMenuSearch = (props: { children: any[]; showType?: boolean; hide
|
||||
.includes(lowerSearchValue)
|
||||
);
|
||||
});
|
||||
}, [searchValue, items]);
|
||||
};
|
||||
|
||||
// 最终结果项
|
||||
const resultItems = useMemo<MenuProps['items']>(() => {
|
||||
// 递归处理菜单项,传递每一层的filteredItems
|
||||
const generateResultItems = (items: any[], name, parentItems: Set<any> = new Set()): MenuProps['items'] => {
|
||||
const res = [];
|
||||
try {
|
||||
// 如果满足条件则显示搜索框
|
||||
if (!hideSearch && (items.length > 10 || searchValue)) {
|
||||
res.push({
|
||||
key: `search-${uid()}`,
|
||||
Component: () => (
|
||||
<SearchFields name={name} value={searchValue} onChange={(val: string) => setSearchValue(val)} />
|
||||
),
|
||||
onClick({ domEvent }) {
|
||||
domEvent.stopPropagation();
|
||||
},
|
||||
...(showType ? { isMenuType: true } : {}),
|
||||
});
|
||||
}
|
||||
|
||||
// 如果有匹配的项目,渲染过滤后的项
|
||||
if (limitedSearchedItems.length > 0) {
|
||||
limitedSearchedItems.forEach((item) => {
|
||||
// 如果是子菜单或分组项,递归处理
|
||||
if (['subMenu', 'itemGroup'].includes(item.type)) {
|
||||
// 避免动态渲染hooks
|
||||
const childItems = item.children
|
||||
? // eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
useMenuSearch({
|
||||
children: item.children,
|
||||
showType,
|
||||
hideSearch,
|
||||
name: item.name,
|
||||
})
|
||||
: [];
|
||||
res.push({ ...item, children: childItems });
|
||||
} else {
|
||||
res.push(item);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 没有匹配项时显示空状态
|
||||
res.push({
|
||||
key: 'empty',
|
||||
style: { height: 150 },
|
||||
Component: () => (
|
||||
<div onClick={(e) => e.stopPropagation()}>
|
||||
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
|
||||
</div>
|
||||
),
|
||||
...(showType ? { isMenuType: true } : {}),
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
res.push(...limitedSearchedItems);
|
||||
// 如果满足条件则显示搜索框
|
||||
if (!hideSearch && (items.length > 10 || searchValue) && !['subMenu', 'itemGroup'].includes(items[0]?.type)) {
|
||||
res.push({
|
||||
key: `search-${uid()}`,
|
||||
Component: () => {
|
||||
return (
|
||||
<SearchFields
|
||||
name={name}
|
||||
value={!currentName || currentName === name ? searchValue : ''}
|
||||
onChange={(val: string) => {
|
||||
currentName = name;
|
||||
setSearchValue(val);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
onClick({ domEvent }) {
|
||||
domEvent.stopPropagation();
|
||||
},
|
||||
...(showType ? { isMenuType: true } : {}),
|
||||
});
|
||||
}
|
||||
|
||||
// 递归处理所有项,包含子菜单
|
||||
items.forEach((item) => {
|
||||
if (parentItems.has(item)) return;
|
||||
|
||||
parentItems.add(item);
|
||||
|
||||
// 过滤当前项是否匹配搜索条件
|
||||
if (['subMenu', 'itemGroup'].includes(item.type)) {
|
||||
// 对子菜单项进行递归处理
|
||||
const result =
|
||||
!currentName || currentName === item.name ? filteredItems(item.children.concat(), item.name) : item.children;
|
||||
const filteredChildren = generateResultItems(result, item.name, parentItems);
|
||||
res.push({ ...item, children: filteredChildren });
|
||||
} else {
|
||||
// 处理非子菜单项
|
||||
res.push(item);
|
||||
}
|
||||
});
|
||||
|
||||
// 如果没有匹配项时显示空状态
|
||||
if (items.length === 0) {
|
||||
res.push({
|
||||
key: 'empty',
|
||||
style: { height: 150 },
|
||||
Component: () => (
|
||||
<div onClick={(e) => e.stopPropagation()}>
|
||||
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
|
||||
</div>
|
||||
),
|
||||
...(showType ? { isMenuType: true } : {}),
|
||||
});
|
||||
}
|
||||
|
||||
return res;
|
||||
}, [hideSearch, limitedSearchedItems, searchValue, showType]);
|
||||
};
|
||||
|
||||
// 获取最终的结果项,处理根级菜单项
|
||||
const resultItems = generateResultItems(filteredItems(children?.concat() || [], name), name);
|
||||
|
||||
return children ? resultItems : undefined;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user