feat: upgrade to v1.2.0 with model param validation and UI improvements

- Upgrade iflow-engine-base to ^2.0.0
- Add sanitizeModelParams for robust model operation validation
- Add try-catch error handling for render mode and model tool calls
- Preserve tree scroll position across tab switches
- Optimize tree node reveal with visibility check and centered scrolling
- Refactor collectModelParams to support multi-model grouping
- Fix tree CSS: remove duplicates, constrain overflow, improve layout
- Move version label to bottom-left
- Rebuild demo libs
This commit is contained in:
yuding
2026-03-02 09:45:59 +08:00
parent 837177f3f2
commit 0ccc891d7c
12 changed files with 4781 additions and 4457 deletions

View File

@@ -82,6 +82,11 @@ interface TransformedNodeData extends EngineTreeNode {
_modelUrl: string;
}
interface ModelParam {
url: string;
ids: number[];
}
// ============================================================================
// 工具函数
// ============================================================================
@@ -123,14 +128,38 @@ async function hashIds(ids: string[]): Promise<string> {
* 递归收集节点及其所有子孙节点的 ids
* 用于父级节点操作时,获取其下所有叶子节点对应的构件 ids
*/
function collectAllIds(node: BimTreeNode): string[] {
const result: string[] = [];
const data = node.config.data as TransformedNodeData | undefined;
if (data?.ids?.length) {
result.push(...data.ids);
}
for (const child of node.children || []) {
result.push(...collectAllIds(child));
function collectModelParams(node: BimTreeNode): ModelParam[] {
const grouped = new Map<string, Set<number>>();
const collect = (current: BimTreeNode): void => {
const data = current.config.data as TransformedNodeData | undefined;
const modelUrl = data?._modelUrl;
if (modelUrl && data?.ids?.length) {
let idSet = grouped.get(modelUrl);
if (!idSet) {
idSet = new Set<number>();
grouped.set(modelUrl, idSet);
}
for (const rawId of data.ids) {
const id = Number(rawId);
if (Number.isFinite(id)) {
idSet.add(id);
}
}
}
for (const child of current.children || []) {
collect(child);
}
};
collect(node);
const result: ModelParam[] = [];
for (const [url, idSet] of grouped) {
if (idSet.size > 0) {
result.push({ url, ids: Array.from(idSet) });
}
}
return result;
}
@@ -337,19 +366,8 @@ export class ConstructTreeManagerBtn extends BaseManager {
* 勾选 → showModel取消勾选 → hideModels
*/
onNodeCheck: (node) => {
const nodeData = node.config.data as TransformedNodeData | undefined;
if (!nodeData?._modelUrl) return;
const ids = nodeData.ids?.length
? nodeData.ids
: collectAllIds(node);
if (!ids.length) return;
const modelParam = [{
url: nodeData._modelUrl,
ids: ids.map(Number)
}];
const modelParam = collectModelParams(node);
if (!modelParam.length) return;
if (node.checkState === TreeNodeCheckState.Checked) {
this.registry.engine3d?.showModel(modelParam);
@@ -362,19 +380,8 @@ export class ConstructTreeManagerBtn extends BaseManager {
* 节点选中回调 - 高亮并跳转到模型构件
*/
onNodeSelect: (node) => {
const nodeData = node.config.data as TransformedNodeData | undefined;
if (!nodeData?._modelUrl) return;
const ids = nodeData.ids?.length
? nodeData.ids
: collectAllIds(node);
if (!ids.length) return;
const modelParam = [{
url: nodeData._modelUrl,
ids: ids.map(Number)
}];
const modelParam = collectModelParams(node);
if (!modelParam.length) return;
this.registry.engine3d?.unhighlightAllModels();
this.registry.engine3d?.highlightModel(modelParam);
@@ -438,7 +445,6 @@ export class ConstructTreeManagerBtn extends BaseManager {
],
activeId: 'component',
onChange: () => {
resetAllTrees();
this.dialog?.fitWidth();
}
});