修改新增分类冒泡及搜索展开问题
This commit is contained in:
parent
395945271f
commit
fc7ea534b7
|
|
@ -43,6 +43,7 @@ export default function DeviceManager({ title }: TermManagerProps) {
|
||||||
const [pageSize, setPageSize] = useState(10);
|
const [pageSize, setPageSize] = useState(10);
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
const [expandedRowKeys, setExpandedRowKeys] = useState<string[]>([]);
|
const [expandedRowKeys, setExpandedRowKeys] = useState<string[]>([]);
|
||||||
|
const [lastExpandedKeys, setLastExpandedKeys] = useState<string[]>([]); // 新增:保存最后的展开状态
|
||||||
|
|
||||||
// ... 保持原有的 API 调用和逻辑 ...
|
// ... 保持原有的 API 调用和逻辑 ...
|
||||||
|
|
||||||
|
|
@ -119,8 +120,8 @@ export default function DeviceManager({ title }: TermManagerProps) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (networkTypeTerms && systemTypeTerms && deviceTypeTerms) {
|
if (networkTypeTerms && systemTypeTerms && deviceTypeTerms) {
|
||||||
if (!searchValue) {
|
if (!searchValue) {
|
||||||
// 清空展开状态
|
// 恢复到最后保存的展开状态
|
||||||
setExpandedRowKeys([]);
|
setExpandedRowKeys(lastExpandedKeys);
|
||||||
|
|
||||||
// 构建正常显示的完整树形结构
|
// 构建正常显示的完整树形结构
|
||||||
const buildNetworkTypeTree = (items: any[]): any[] => {
|
const buildNetworkTypeTree = (items: any[]): any[] => {
|
||||||
|
|
@ -207,7 +208,7 @@ export default function DeviceManager({ title }: TermManagerProps) {
|
||||||
const finalTreeData = addSystemAndFaultTypes(networkTypeTree);
|
const finalTreeData = addSystemAndFaultTypes(networkTypeTree);
|
||||||
setTreeData(finalTreeData);
|
setTreeData(finalTreeData);
|
||||||
} else {
|
} else {
|
||||||
// 搜索逻辑
|
// 搜索逻辑:构建完整树结构,但只显示匹配项及其路径
|
||||||
const searchTerm = searchValue.toLowerCase().trim();
|
const searchTerm = searchValue.toLowerCase().trim();
|
||||||
const allTerms = [...networkTypeTerms, ...systemTypeTerms, ...deviceTypeTerms];
|
const allTerms = [...networkTypeTerms, ...systemTypeTerms, ...deviceTypeTerms];
|
||||||
|
|
||||||
|
|
@ -222,8 +223,8 @@ export default function DeviceManager({ title }: TermManagerProps) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 找到需要展开的所有祖先节点
|
// 找到所有匹配项的祖先节点
|
||||||
const findAllAncestors = (termId: string): string[] => {
|
const findAncestors = (termId: string): string[] => {
|
||||||
const ancestors: string[] = [];
|
const ancestors: string[] = [];
|
||||||
let currentTerm = allTerms.find(t => t.id === termId);
|
let currentTerm = allTerms.find(t => t.id === termId);
|
||||||
|
|
||||||
|
|
@ -235,58 +236,187 @@ export default function DeviceManager({ title }: TermManagerProps) {
|
||||||
return ancestors;
|
return ancestors;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 收集所有需要展开的节点
|
// 收集需要显示的节点(匹配项 + 祖先节点)
|
||||||
const expandKeys = new Set<string>();
|
const visibleNodes = new Set<string>();
|
||||||
const relevantTermIds = new Set<string>();
|
|
||||||
|
|
||||||
matchedTerms.forEach(matched => {
|
matchedTerms.forEach(matched => {
|
||||||
relevantTermIds.add(matched.id);
|
visibleNodes.add(matched.id);
|
||||||
const ancestors = findAllAncestors(matched.id);
|
findAncestors(matched.id).forEach(ancestorId => {
|
||||||
ancestors.forEach(ancestorId => {
|
visibleNodes.add(ancestorId);
|
||||||
expandKeys.add(ancestorId);
|
|
||||||
relevantTermIds.add(ancestorId);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// 只保留相关的项目来构建搜索结果树
|
// 构建完整的树形结构,但添加可见性标记
|
||||||
const relevantTerms = allTerms.filter(term => relevantTermIds.has(term.id));
|
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 buildSearchTree = (items: any[]): any[] => {
|
const treeItem = itemMap.get(item.id);
|
||||||
const itemMap = new Map();
|
if (item.parentId && itemMap.has(item.parentId)) {
|
||||||
|
const parent = itemMap.get(item.parentId);
|
||||||
// 初始化所有相关项
|
parent.children.push(treeItem);
|
||||||
items.forEach(item => {
|
} else {
|
||||||
itemMap.set(item.id, {
|
roots.push(treeItem);
|
||||||
...item,
|
}
|
||||||
key: item.id,
|
|
||||||
children: [],
|
|
||||||
isMatched: matchedTerms.some(m => m.id === item.id)
|
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
const roots: any[] = [];
|
return roots;
|
||||||
|
};
|
||||||
|
|
||||||
// 建立父子关系
|
const addSystemAndFaultTypes = (networkTypeTree: any[]): any[] => {
|
||||||
items.forEach(item => {
|
return networkTypeTree.map(networkType => {
|
||||||
const treeItem = itemMap.get(item.id);
|
const systemChildren = systemTypeTerms.filter(
|
||||||
if (item.parentId && itemMap.has(item.parentId)) {
|
(t) => t.parentId === networkType.id
|
||||||
const parent = itemMap.get(item.parentId);
|
);
|
||||||
parent.children.push(treeItem);
|
|
||||||
} else {
|
|
||||||
roots.push(treeItem);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return roots;
|
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 searchResultTree = buildSearchTree(relevantTerms);
|
// 过滤树结构,只保留可见的节点
|
||||||
setTreeData(searchResultTree);
|
const filterVisibleNodes = (nodes: any[]): any[] => {
|
||||||
setExpandedRowKeys(Array.from(expandKeys));
|
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) => {
|
const handleSearch = (value: string) => {
|
||||||
setSearchValue(value);
|
setSearchValue(value);
|
||||||
|
|
@ -602,7 +732,7 @@ export default function DeviceManager({ title }: TermManagerProps) {
|
||||||
dataSource={treeData}
|
dataSource={treeData}
|
||||||
expandable={{
|
expandable={{
|
||||||
expandedRowKeys: expandedRowKeys,
|
expandedRowKeys: expandedRowKeys,
|
||||||
onExpandedRowsChange: (keys) => setExpandedRowKeys(keys.map(key => String(key))),
|
onExpand: handleExpand,
|
||||||
expandRowByClick: true,
|
expandRowByClick: true,
|
||||||
indentSize: 20,
|
indentSize: 20,
|
||||||
}}
|
}}
|
||||||
|
|
@ -677,7 +807,7 @@ export default function DeviceManager({ title }: TermManagerProps) {
|
||||||
<Button
|
<Button
|
||||||
type="text"
|
type="text"
|
||||||
icon={<PlusOutlined />}
|
icon={<PlusOutlined />}
|
||||||
onClick={() => handleAdd(record)}
|
onClick={(e) => {e.stopPropagation();handleAdd(record)}}
|
||||||
className="text-green-600 hover:text-green-700 hover:bg-green-50"
|
className="text-green-600 hover:text-green-700 hover:bg-green-50"
|
||||||
size="small"
|
size="small"
|
||||||
title="添加子项"
|
title="添加子项"
|
||||||
|
|
@ -686,7 +816,7 @@ export default function DeviceManager({ title }: TermManagerProps) {
|
||||||
<Button
|
<Button
|
||||||
type="text"
|
type="text"
|
||||||
icon={<EditOutlined />}
|
icon={<EditOutlined />}
|
||||||
onClick={() => handleEdit(record)}
|
onClick={(e) => {e.stopPropagation();handleEdit(record)}}
|
||||||
className="text-blue-600 hover:text-blue-700 hover:bg-blue-50"
|
className="text-blue-600 hover:text-blue-700 hover:bg-blue-50"
|
||||||
size="small"
|
size="small"
|
||||||
title="编辑"
|
title="编辑"
|
||||||
|
|
@ -695,7 +825,7 @@ export default function DeviceManager({ title }: TermManagerProps) {
|
||||||
type="text"
|
type="text"
|
||||||
danger
|
danger
|
||||||
icon={<DeleteOutlined />}
|
icon={<DeleteOutlined />}
|
||||||
onClick={() => handleDelete(record)}
|
onClick={(e) => {e.stopPropagation();handleDelete(record)}}
|
||||||
size="small"
|
size="small"
|
||||||
title="删除"
|
title="删除"
|
||||||
className="hover:bg-red-50"
|
className="hover:bg-red-50"
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ export default function DeviceTypeSelect({
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [isInitialized, setIsInitialized] = useState(false); // 添加初始化标记
|
||||||
|
|
||||||
// 动态构建查询条件
|
// 动态构建查询条件
|
||||||
const whereCondition = {
|
const whereCondition = {
|
||||||
|
|
@ -43,15 +44,29 @@ export default function DeviceTypeSelect({
|
||||||
// 使用 useRef 来跟踪之前的 systemTypeId
|
// 使用 useRef 来跟踪之前的 systemTypeId
|
||||||
const prevSystemTypeIdRef = useRef<string | undefined>(systemTypeId);
|
const prevSystemTypeIdRef = useRef<string | undefined>(systemTypeId);
|
||||||
|
|
||||||
// 当系统类型改变时,清空当前选择
|
// 当系统类型改变时,清空当前选择,只有在已初始化且用户主动更改时才清空
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (prevSystemTypeIdRef.current !== systemTypeId) {
|
if (prevSystemTypeIdRef.current !== systemTypeId) {
|
||||||
prevSystemTypeIdRef.current = systemTypeId;
|
prevSystemTypeIdRef.current = systemTypeId;
|
||||||
if (onChange && value) {
|
|
||||||
|
// 只有在已初始化且有值的情况下才清空
|
||||||
|
if (isInitialized && onChange && value) {
|
||||||
onChange(undefined);
|
onChange(undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 标记为已初始化
|
||||||
|
if (!isInitialized) {
|
||||||
|
setIsInitialized(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, [systemTypeId]);
|
}, [systemTypeId, isInitialized]);
|
||||||
|
|
||||||
|
// 当值变化时,重置初始化状态(用于新建场景)
|
||||||
|
useEffect(() => {
|
||||||
|
if (!value && !systemTypeId) {
|
||||||
|
setIsInitialized(false);
|
||||||
|
}
|
||||||
|
}, [value, systemTypeId]);
|
||||||
|
|
||||||
// 处理选项数据
|
// 处理选项数据
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ server {
|
||||||
# 监听80端口
|
# 监听80端口
|
||||||
listen 80;
|
listen 80;
|
||||||
# 服务器域名/IP地址,使用环境变量
|
# 服务器域名/IP地址,使用环境变量
|
||||||
server_name 192.168.77.194;
|
server_name 192.168.142.194;
|
||||||
|
|
||||||
# 基础性能优化配置
|
# 基础性能优化配置
|
||||||
# 启用tcp_nopush以优化数据发送
|
# 启用tcp_nopush以优化数据发送
|
||||||
|
|
@ -100,7 +100,7 @@ server {
|
||||||
# 仅供内部使用
|
# 仅供内部使用
|
||||||
internal;
|
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;
|
proxy_pass_request_body off;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue