修改新增分类冒泡及搜索展开问题

This commit is contained in:
Your Name 2025-07-09 11:02:54 +08:00
parent 395945271f
commit fc7ea534b7
3 changed files with 198 additions and 53 deletions

View File

@ -43,6 +43,7 @@ export default function DeviceManager({ title }: TermManagerProps) {
const [pageSize, setPageSize] = useState(10);
const [currentPage, setCurrentPage] = useState(1);
const [expandedRowKeys, setExpandedRowKeys] = useState<string[]>([]);
const [lastExpandedKeys, setLastExpandedKeys] = useState<string[]>([]); // 新增:保存最后的展开状态
// ... 保持原有的 API 调用和逻辑 ...
@ -119,8 +120,8 @@ export default function DeviceManager({ title }: TermManagerProps) {
useEffect(() => {
if (networkTypeTerms && systemTypeTerms && deviceTypeTerms) {
if (!searchValue) {
// 清空展开状态
setExpandedRowKeys([]);
// 恢复到最后保存的展开状态
setExpandedRowKeys(lastExpandedKeys);
// 构建正常显示的完整树形结构
const buildNetworkTypeTree = (items: any[]): any[] => {
@ -207,7 +208,7 @@ export default function DeviceManager({ title }: TermManagerProps) {
const finalTreeData = addSystemAndFaultTypes(networkTypeTree);
setTreeData(finalTreeData);
} else {
// 搜索逻辑
// 搜索逻辑:构建完整树结构,但只显示匹配项及其路径
const searchTerm = searchValue.toLowerCase().trim();
const allTerms = [...networkTypeTerms, ...systemTypeTerms, ...deviceTypeTerms];
@ -222,8 +223,8 @@ export default function DeviceManager({ title }: TermManagerProps) {
return;
}
// 找到需要展开的所有祖先节点
const findAllAncestors = (termId: string): string[] => {
// 找到所有匹配项的祖先节点
const findAncestors = (termId: string): string[] => {
const ancestors: string[] = [];
let currentTerm = allTerms.find(t => t.id === termId);
@ -235,39 +236,22 @@ export default function DeviceManager({ title }: TermManagerProps) {
return ancestors;
};
// 收集所有需要展开的节点
const expandKeys = new Set<string>();
const relevantTermIds = new Set<string>();
// 收集需要显示的节点(匹配项 + 祖先节点)
const visibleNodes = new Set<string>();
matchedTerms.forEach(matched => {
relevantTermIds.add(matched.id);
const ancestors = findAllAncestors(matched.id);
ancestors.forEach(ancestorId => {
expandKeys.add(ancestorId);
relevantTermIds.add(ancestorId);
});
});
// 只保留相关的项目来构建搜索结果树
const relevantTerms = allTerms.filter(term => relevantTermIds.has(term.id));
// 构建搜索结果的树形结构
const buildSearchTree = (items: any[]): any[] => {
const itemMap = new Map();
// 初始化所有相关项
items.forEach(item => {
itemMap.set(item.id, {
...item,
key: item.id,
children: [],
isMatched: matchedTerms.some(m => m.id === item.id)
visibleNodes.add(matched.id);
findAncestors(matched.id).forEach(ancestorId => {
visibleNodes.add(ancestorId);
});
});
// 构建完整的树形结构,但添加可见性标记
const buildCompleteTreeWithVisibility = (): any[] => {
// 先按照原有逻辑构建完整的树形结构
const buildNetworkTypeTree = (items: any[]): any[] => {
const itemMap = new Map(items.map(item => [item.id, { ...item, children: [] }]));
const roots: any[] = [];
// 建立父子关系
items.forEach(item => {
const treeItem = itemMap.get(item.id);
if (item.parentId && itemMap.has(item.parentId)) {
@ -281,12 +265,158 @@ export default function DeviceManager({ title }: TermManagerProps) {
return roots;
};
const searchResultTree = buildSearchTree(relevantTerms);
setTreeData(searchResultTree);
setExpandedRowKeys(Array.from(expandKeys));
const addSystemAndFaultTypes = (networkTypeTree: any[]): any[] => {
return networkTypeTree.map(networkType => {
const systemChildren = systemTypeTerms.filter(
(t) => t.parentId === networkType.id
);
const buildSystemTypeTree = (systemTypes: any[]): any[] => {
return systemTypes.map((systemType) => {
const childSystemTypes = systemTypeTerms.filter(
(t) => t.parentId === systemType.id && t.taxonomyId === systemTypeTaxonomy?.id
);
const faultTypes = deviceTypeTerms.filter(
(t) => t.parentId === systemType.id
);
const processedChildSystems = childSystemTypes.length > 0
? buildSystemTypeTree(childSystemTypes)
: [];
const processedFaultTypes = faultTypes.map((fault) => ({
...fault,
key: fault.id,
isMatched: matchedTerms.some(m => m.id === fault.id),
isVisible: visibleNodes.has(fault.id),
}));
return {
...systemType,
key: systemType.id,
isMatched: matchedTerms.some(m => m.id === systemType.id),
isVisible: visibleNodes.has(systemType.id),
children: [
...processedChildSystems,
...processedFaultTypes
],
};
});
};
const processedSystemChildren = buildSystemTypeTree(systemChildren);
let processedChildNetworkTypes: any[] = [];
if (networkType.children && networkType.children.length > 0) {
processedChildNetworkTypes = addSystemAndFaultTypes(networkType.children);
}
const allChildren = [
...processedChildNetworkTypes,
...processedSystemChildren
];
return {
...networkType,
key: networkType.id,
isMatched: matchedTerms.some(m => m.id === networkType.id),
isVisible: visibleNodes.has(networkType.id),
children: allChildren,
};
});
};
const networkTypeTree = buildNetworkTypeTree(networkTypeTerms);
return addSystemAndFaultTypes(networkTypeTree);
};
// 过滤树结构,只保留可见的节点
const filterVisibleNodes = (nodes: any[]): any[] => {
return nodes
.filter(node => node.isVisible)
.map(node => ({
...node,
children: node.children ? filterVisibleNodes(node.children) : []
}));
};
// 构建完整树结构
const completeTree = buildCompleteTreeWithVisibility();
// 过滤只显示可见节点
const filteredTree = filterVisibleNodes(completeTree);
setTreeData(filteredTree);
// 自动展开有匹配子项的节点
const autoExpandKeys = new Set<string>();
matchedTerms.forEach(matched => {
const ancestors = findAncestors(matched.id);
ancestors.forEach(ancestorId => autoExpandKeys.add(ancestorId));
});
setExpandedRowKeys(Array.from(autoExpandKeys));
}
}
}, [networkTypeTerms, systemTypeTerms, deviceTypeTerms, searchValue, networkTypeTaxonomy, systemTypeTaxonomy, deviceTypeTaxonomy]);
}, [networkTypeTerms, systemTypeTerms, deviceTypeTerms, searchValue, networkTypeTaxonomy, systemTypeTaxonomy, deviceTypeTaxonomy, lastExpandedKeys]);
// 添加一个自定义的展开处理函数
const handleExpand = (expanded: boolean, record: any) => {
const key = record.key;
let newExpandedKeys = [...expandedRowKeys];
if (expanded) {
// 展开节点时,如果是搜索状态,需要动态加载完整的子节点
if (searchValue) {
const allTerms = [...(networkTypeTerms || []), ...(systemTypeTerms || []), ...(deviceTypeTerms || [])];
// 更新treeData为展开的节点添加所有子项
const updateTreeDataWithAllChildren = (nodes: any[]): any[] => {
return nodes.map(node => {
if (node.key === key) {
// 找到当前节点的所有直接子项
const allDirectChildren = allTerms.filter(term => term.parentId === node.id);
// 为每个子项添加标记
const enrichedChildren = allDirectChildren.map(child => ({
...child,
key: child.id,
isMatched: child.name.toLowerCase().includes(searchValue.toLowerCase()),
isVisible: true,
children: [] // 子项的子项会在后续展开时动态加载
}));
return {
...node,
children: enrichedChildren
};
} else if (node.children && node.children.length > 0) {
return {
...node,
children: updateTreeDataWithAllChildren(node.children)
};
}
return node;
});
};
setTreeData(prevData => updateTreeDataWithAllChildren(prevData));
}
if (!newExpandedKeys.includes(key)) {
newExpandedKeys.push(key);
}
} else {
newExpandedKeys = newExpandedKeys.filter(k => k !== key);
}
setExpandedRowKeys(newExpandedKeys);
// 在非搜索状态下,更新最后的展开状态
if (!searchValue) {
setLastExpandedKeys(newExpandedKeys);
}
};
const handleSearch = (value: string) => {
setSearchValue(value);
@ -602,7 +732,7 @@ export default function DeviceManager({ title }: TermManagerProps) {
dataSource={treeData}
expandable={{
expandedRowKeys: expandedRowKeys,
onExpandedRowsChange: (keys) => setExpandedRowKeys(keys.map(key => String(key))),
onExpand: handleExpand,
expandRowByClick: true,
indentSize: 20,
}}
@ -677,7 +807,7 @@ export default function DeviceManager({ title }: TermManagerProps) {
<Button
type="text"
icon={<PlusOutlined />}
onClick={() => handleAdd(record)}
onClick={(e) => {e.stopPropagation();handleAdd(record)}}
className="text-green-600 hover:text-green-700 hover:bg-green-50"
size="small"
title="添加子项"
@ -686,7 +816,7 @@ export default function DeviceManager({ title }: TermManagerProps) {
<Button
type="text"
icon={<EditOutlined />}
onClick={() => handleEdit(record)}
onClick={(e) => {e.stopPropagation();handleEdit(record)}}
className="text-blue-600 hover:text-blue-700 hover:bg-blue-50"
size="small"
title="编辑"
@ -695,7 +825,7 @@ export default function DeviceManager({ title }: TermManagerProps) {
type="text"
danger
icon={<DeleteOutlined />}
onClick={() => handleDelete(record)}
onClick={(e) => {e.stopPropagation();handleDelete(record)}}
size="small"
title="删除"
className="hover:bg-red-50"

View File

@ -26,6 +26,7 @@ export default function DeviceTypeSelect({
[]
);
const [loading, setLoading] = useState(false);
const [isInitialized, setIsInitialized] = useState(false); // 添加初始化标记
// 动态构建查询条件
const whereCondition = {
@ -43,15 +44,29 @@ export default function DeviceTypeSelect({
// 使用 useRef 来跟踪之前的 systemTypeId
const prevSystemTypeIdRef = useRef<string | undefined>(systemTypeId);
// 当系统类型改变时,清空当前选择
// 当系统类型改变时,清空当前选择,只有在已初始化且用户主动更改时才清空
useEffect(() => {
if (prevSystemTypeIdRef.current !== systemTypeId) {
prevSystemTypeIdRef.current = systemTypeId;
if (onChange && value) {
// 只有在已初始化且有值的情况下才清空
if (isInitialized && onChange && value) {
onChange(undefined);
}
// 标记为已初始化
if (!isInitialized) {
setIsInitialized(true);
}
}, [systemTypeId]);
}
}, [systemTypeId, isInitialized]);
// 当值变化时,重置初始化状态(用于新建场景)
useEffect(() => {
if (!value && !systemTypeId) {
setIsInitialized(false);
}
}, [value, systemTypeId]);
// 处理选项数据
useEffect(() => {

View File

@ -2,7 +2,7 @@ server {
# 监听80端口
listen 80;
# 服务器域名/IP地址使用环境变量
server_name 192.168.77.194;
server_name 192.168.142.194;
# 基础性能优化配置
# 启用tcp_nopush以优化数据发送
@ -100,7 +100,7 @@ server {
# 仅供内部使用
internal;
# 代理到认证服务
proxy_pass http://192.168.77.194:3000/auth/file;
proxy_pass http://192.168.142.194:3000/auth/file;
# 请求优化:不传递请求体
proxy_pass_request_body off;