refactor(managers): accept registry parameter via constructor injection

All 16 managers now receive ManagerRegistry instance through constructor
instead of calling ManagerRegistry.getInstance(). This enables each
BimEngine instance to have its own isolated set of managers.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
yuding
2026-02-28 10:08:36 +08:00
parent 963e0d6cad
commit 73edf0b3b8
16 changed files with 86 additions and 30 deletions

View File

@@ -18,8 +18,8 @@ export class AiChatManager {
/** 是否已初始化 */ /** 是否已初始化 */
private initialized = false; private initialized = false;
constructor() { constructor(registry: ManagerRegistry) {
this.registry = ManagerRegistry.getInstance(); this.registry = registry;
} }
/** /**

View File

@@ -6,6 +6,7 @@ import { BimButtonGroup } from '../components/button-group';
import type { ButtonGroupOptions } from '../components/button-group/index.type'; import type { ButtonGroupOptions } from '../components/button-group/index.type';
import type { ThemeConfig } from '../themes/types'; import type { ThemeConfig } from '../themes/types';
import { BaseManager } from '../core/base-manager'; import { BaseManager } from '../core/base-manager';
import { ManagerRegistry } from '../core/manager-registry';
/** /**
* 按钮组管理器 * 按钮组管理器
@@ -17,8 +18,8 @@ export class ButtonGroupManager extends BaseManager {
/** 容器元素 */ /** 容器元素 */
private container: HTMLElement; private container: HTMLElement;
constructor(container: HTMLElement) { constructor(container: HTMLElement, registry: ManagerRegistry) {
super(); super(registry);
this.container = container; this.container = container;
} }
@@ -31,6 +32,7 @@ export class ButtonGroupManager extends BaseManager {
public create(id: string, options: Omit<ButtonGroupOptions, 'container'>): BimButtonGroup { public create(id: string, options: Omit<ButtonGroupOptions, 'container'>): BimButtonGroup {
const group = new BimButtonGroup({ const group = new BimButtonGroup({
container: this.container, container: this.container,
registry: this.registry,
...options ...options
}); });

View File

@@ -1,4 +1,5 @@
import { BaseManager } from '../core/base-manager'; import { BaseManager } from '../core/base-manager';
import { ManagerRegistry } from '../core/manager-registry';
import { BimCollapse } from '../components/collapse/index'; import { BimCollapse } from '../components/collapse/index';
import { BimTab } from '../components/tab'; import { BimTab } from '../components/tab';
import { t } from '../services/locale'; import { t } from '../services/locale';
@@ -12,8 +13,8 @@ export class ComponentDetailManager extends BaseManager {
private tabInstance: BimTab | null = null; private tabInstance: BimTab | null = null;
private propertiesData: any = null; private propertiesData: any = null;
constructor() { constructor(registry: ManagerRegistry) {
super(); super(registry);
} }
public init(): void { public init(): void {

View File

@@ -16,6 +16,7 @@
import type { ButtonGroupColors, ButtonConfig } from '../components/button-group/index.type'; import type { ButtonGroupColors, ButtonConfig } from '../components/button-group/index.type';
import { BaseManager } from '../core/base-manager'; import { BaseManager } from '../core/base-manager';
import { ManagerRegistry } from '../core/manager-registry';
import { BimButtonGroup } from '../components/button-group'; import { BimButtonGroup } from '../components/button-group';
import { BimTree } from '../components/tree'; import { BimTree } from '../components/tree';
import { TreeNodeConfig, TreeNodeCheckState } from '../components/tree/types'; import { TreeNodeConfig, TreeNodeCheckState } from '../components/tree/types';
@@ -99,13 +100,23 @@ interface TransformedNodeData extends EngineTreeNode {
* @example * @example
* hashIds(["350518", "350520"]) // => "a1b2c3d4e5f6..." * hashIds(["350518", "350520"]) // => "a1b2c3d4e5f6..."
*/ */
function fnv1a32(input: string, seed: number): number {
let h = seed >>> 0;
for (let i = 0; i < input.length; i++) {
const c = input.charCodeAt(i);
h ^= c & 0xff;
h = Math.imul(h, 0x01000193);
h ^= (c >>> 8) & 0xff;
h = Math.imul(h, 0x01000193);
}
return h >>> 0;
}
async function hashIds(ids: string[]): Promise<string> { async function hashIds(ids: string[]): Promise<string> {
const str = JSON.stringify(ids); const str = JSON.stringify(ids);
const data = new TextEncoder().encode(str); const h1 = fnv1a32(str, 0x811c9dc5);
const buf = await crypto.subtle.digest('SHA-256', data); const h2 = fnv1a32(str, 0x811c9dc5 ^ 0x9e3779b9);
return Array.from(new Uint8Array(buf)) return `${h1.toString(16).padStart(8, '0')}${h2.toString(16).padStart(8, '0')}`;
.map(b => b.toString(16).padStart(2, '0'))
.join('');
} }
/** /**
@@ -235,8 +246,8 @@ export class ConstructTreeManagerBtn extends BaseManager {
* 创建构件树管理器 * 创建构件树管理器
* @param container - 按钮挂载的容器元素 * @param container - 按钮挂载的容器元素
*/ */
constructor(container: HTMLElement) { constructor(container: HTMLElement, registry: ManagerRegistry) {
super(); super(registry);
this.container = container; this.container = container;
this.init(); this.init();
} }
@@ -258,7 +269,8 @@ export class ConstructTreeManagerBtn extends BaseManager {
direction: 'column', direction: 'column',
position: 'top-left', position: 'top-left',
align: 'vertical', align: 'vertical',
expand: 'up' expand: 'up',
registry: this.registry
}); });
this.toolbar.init(); this.toolbar.init();
this.toolbar.addGroup('construct-tree'); this.toolbar.addGroup('construct-tree');

View File

@@ -3,13 +3,14 @@ import type { DialogOptions } from '../components/dialog/index.type';
import type { ThemeConfig } from '../themes/types'; import type { ThemeConfig } from '../themes/types';
import { themeManager } from '../services/theme'; import { themeManager } from '../services/theme';
import { BaseManager } from '../core/base-manager'; import { BaseManager } from '../core/base-manager';
import { ManagerRegistry } from '../core/manager-registry';
export class DialogManager extends BaseManager { export class DialogManager extends BaseManager {
private container: HTMLElement; private container: HTMLElement;
private activeDialogs: BimDialog[] = []; private activeDialogs: BimDialog[] = [];
constructor(container: HTMLElement) { constructor(container: HTMLElement, registry: ManagerRegistry) {
super(); super(registry);
this.container = container; this.container = container;
} }

View File

@@ -1,4 +1,5 @@
import { BaseDialogManager } from '../core/base-dialog-manager'; import { BaseDialogManager } from '../core/base-dialog-manager';
import { ManagerRegistry } from '../core/manager-registry';
import { t } from '../services/locale'; import { t } from '../services/locale';
import type { EngineInfo } from '../components/engine'; import type { EngineInfo } from '../components/engine';
@@ -7,6 +8,11 @@ export class EngineInfoDialogManager extends BaseDialogManager {
protected get dialogTitle() { return 'info.dialogTitle'; } protected get dialogTitle() { return 'info.dialogTitle'; }
protected get dialogWidth() { return 280; } protected get dialogWidth() { return 280; }
constructor(registry: ManagerRegistry) {
super(registry);
}
public init(): void {} public init(): void {}
protected getDialogPosition() { protected getDialogPosition() {

View File

@@ -23,8 +23,8 @@ export class EngineManager extends BaseManager {
/** 右键菜单管理器 */ /** 右键菜单管理器 */
public rightKey: RightKeyManager | null = null; public rightKey: RightKeyManager | null = null;
constructor(container: HTMLElement) { constructor(container: HTMLElement, registry: ManagerRegistry) {
super(); super(registry);
this.container = container; this.container = container;
} }
@@ -44,11 +44,11 @@ export class EngineManager extends BaseManager {
this.engineInstance = new Engine({ this.engineInstance = new Engine({
container: this.container, container: this.container,
...options, ...options,
}); }, this.registry);
this.engineInstance.init(); this.engineInstance.init();
this.rightKey = new RightKeyManager(this.container); this.rightKey = new RightKeyManager(this.container, this.registry);
this.rightKey.registerHandler((_e) => { this.rightKey.registerHandler((_e) => {
const selected = this.getSelectedComponent(); const selected = this.getSelectedComponent();
@@ -63,7 +63,7 @@ export class EngineManager extends BaseManager {
order: 1, order: 1,
divider: true, divider: true,
onClick: () => { onClick: () => {
const registry = ManagerRegistry.getInstance(); const registry = this.registry;
registry.componentDetail?.show(); registry.componentDetail?.show();
this.rightKey?.hide(); this.rightKey?.hide();
} }

View File

@@ -1,4 +1,5 @@
import { BaseDialogManager } from '../core/base-dialog-manager'; import { BaseDialogManager } from '../core/base-dialog-manager';
import { ManagerRegistry } from '../core/manager-registry';
import { MeasurePanel } from '../components/measure-panel'; import { MeasurePanel } from '../components/measure-panel';
import type { MeasureConfig, MeasureResult } from '../components/measure-panel/types'; import type { MeasureConfig, MeasureResult } from '../components/measure-panel/types';
import { MEASURE_TYPES, getModeBycallBackType, getValueType, type MeasureMode, type CallBackType } from '../types/measure'; import { MEASURE_TYPES, getModeBycallBackType, getValueType, type MeasureMode, type CallBackType } from '../types/measure';
@@ -19,6 +20,10 @@ export class MeasureDialogManager extends BaseDialogManager {
private config: MeasureConfig | null = null; private config: MeasureConfig | null = null;
private unsubscribeMeasureChanged: (() => void) | null = null; private unsubscribeMeasureChanged: (() => void) | null = null;
constructor(registry: ManagerRegistry) {
super(registry);
}
protected get dialogId(): string { protected get dialogId(): string {
return 'measure-dialog'; return 'measure-dialog';
} }

View File

@@ -3,6 +3,7 @@
* 负责管理右键上下文菜单的显示和交互 * 负责管理右键上下文菜单的显示和交互
*/ */
import { BaseManager } from '../core/base-manager'; import { BaseManager } from '../core/base-manager';
import { ManagerRegistry } from '../core/manager-registry';
import { BimRightKey } from '../components/right-key'; import { BimRightKey } from '../components/right-key';
import { BimMenu } from '../components/menu'; import { BimMenu } from '../components/menu';
import { MenuItemConfig } from '../components/menu/item'; import { MenuItemConfig } from '../components/menu/item';
@@ -19,8 +20,8 @@ export class RightKeyManager extends BaseManager {
/** 上下文处理器列表 */ /** 上下文处理器列表 */
private contextHandlers: Array<(e: MouseEvent) => MenuItemConfig[] | null> = []; private contextHandlers: Array<(e: MouseEvent) => MenuItemConfig[] | null> = [];
constructor(container: HTMLElement) { constructor(container: HTMLElement, registry: ManagerRegistry) {
super(); super(registry);
this.container = container; this.container = container;
this.rightKeyPanel = new BimRightKey({ this.rightKeyPanel = new BimRightKey({

View File

@@ -3,6 +3,7 @@
* 负责管理轴向剖切工具对话框的显示、隐藏和剖切面板的交互 * 负责管理轴向剖切工具对话框的显示、隐藏和剖切面板的交互
*/ */
import { BaseDialogManager } from '../core/base-dialog-manager'; import { BaseDialogManager } from '../core/base-dialog-manager';
import { ManagerRegistry } from '../core/manager-registry';
import { SectionAxisPanel } from '../components/section-axis-panel'; import { SectionAxisPanel } from '../components/section-axis-panel';
import type { SectionAxis } from '../components/section-axis-panel/types'; import type { SectionAxis } from '../components/section-axis-panel/types';
@@ -14,6 +15,10 @@ export class SectionAxisDialogManager extends BaseDialogManager {
/** 轴向剖切面板实例 */ /** 轴向剖切面板实例 */
private panel: SectionAxisPanel | null = null; private panel: SectionAxisPanel | null = null;
constructor(registry: ManagerRegistry) {
super(registry);
}
/** 对话框唯一标识 */ /** 对话框唯一标识 */
protected get dialogId(): string { protected get dialogId(): string {
return 'section-axis-dialog'; return 'section-axis-dialog';

View File

@@ -1,4 +1,5 @@
import { BaseDialogManager } from '../core/base-dialog-manager'; import { BaseDialogManager } from '../core/base-dialog-manager';
import { ManagerRegistry } from '../core/manager-registry';
import { SectionBoxPanel } from '../components/section-box-panel'; import { SectionBoxPanel } from '../components/section-box-panel';
import type { SectionBoxRange } from '../components/section-box-panel/types'; import type { SectionBoxRange } from '../components/section-box-panel/types';
@@ -6,6 +7,10 @@ export class SectionBoxDialogManager extends BaseDialogManager {
private panel: SectionBoxPanel | null = null; private panel: SectionBoxPanel | null = null;
private unsubscribeSectionMove: (() => void) | null = null; private unsubscribeSectionMove: (() => void) | null = null;
constructor(registry: ManagerRegistry) {
super(registry);
}
/** 对话框唯一标识 */ /** 对话框唯一标识 */
protected get dialogId(): string { protected get dialogId(): string {
return 'section-box-dialog'; return 'section-box-dialog';

View File

@@ -3,6 +3,7 @@
* 负责管理拾取面剖切工具对话框的显示和交互 * 负责管理拾取面剖切工具对话框的显示和交互
*/ */
import { BaseDialogManager } from '../core/base-dialog-manager'; import { BaseDialogManager } from '../core/base-dialog-manager';
import { ManagerRegistry } from '../core/manager-registry';
import { SectionPlanePanel } from '../components/section-plane-panel'; import { SectionPlanePanel } from '../components/section-plane-panel';
/** /**
@@ -13,6 +14,10 @@ export class SectionPlaneDialogManager extends BaseDialogManager {
/** 剖切面板实例 */ /** 剖切面板实例 */
private panel: SectionPlanePanel | null = null; private panel: SectionPlanePanel | null = null;
constructor(registry: ManagerRegistry) {
super(registry);
}
/** 对话框唯一标识 */ /** 对话框唯一标识 */
protected get dialogId() { return 'section-plane-dialog'; } protected get dialogId() { return 'section-plane-dialog'; }
/** 对话框标题(国际化 key */ /** 对话框标题(国际化 key */

View File

@@ -6,6 +6,7 @@ import type { ButtonGroupColors, ButtonConfig } from '../components/button-group
import { Toolbar } from '../components/button-group/toolbar'; import { Toolbar } from '../components/button-group/toolbar';
import type { ThemeConfig } from '../themes/types'; import type { ThemeConfig } from '../themes/types';
import { BaseManager } from '../core/base-manager'; import { BaseManager } from '../core/base-manager';
import { ManagerRegistry } from '../core/manager-registry';
/** /**
* 工具栏管理器 * 工具栏管理器
@@ -19,8 +20,8 @@ export class ToolbarManager extends BaseManager {
/** 主容器元素 */ /** 主容器元素 */
private container: HTMLElement; private container: HTMLElement;
constructor(container: HTMLElement) { constructor(container: HTMLElement, registry: ManagerRegistry) {
super(); super(registry);
this.container = container; this.container = container;
this.init(); this.init();
} }
@@ -39,7 +40,8 @@ export class ToolbarManager extends BaseManager {
direction: 'row', direction: 'row',
position: 'bottom-right', position: 'bottom-right',
align: 'vertical', align: 'vertical',
expand: 'up' expand: 'up',
registry: this.registry
}); });
this.toolbar.init(); this.toolbar.init();

View File

@@ -3,6 +3,7 @@
* 负责管理漫游模式的控制面板和相关交互 * 负责管理漫游模式的控制面板和相关交互
*/ */
import { BaseManager } from '../core/base-manager'; import { BaseManager } from '../core/base-manager';
import { ManagerRegistry } from '../core/manager-registry';
import { WalkControlPanel } from '../components/walk-control-panel'; import { WalkControlPanel } from '../components/walk-control-panel';
import { WalkPathDialogManager } from './walk-path-dialog-manager'; import { WalkPathDialogManager } from './walk-path-dialog-manager';
@@ -16,13 +17,13 @@ export class WalkControlManager extends BaseManager {
/** 路径漫游对话框管理器 */ /** 路径漫游对话框管理器 */
private pathManager: WalkPathDialogManager | null = null; private pathManager: WalkPathDialogManager | null = null;
constructor() { constructor(registry: ManagerRegistry) {
super(); super(registry);
} }
/** 初始化管理器 */ /** 初始化管理器 */
public init(): void { public init(): void {
this.pathManager = new WalkPathDialogManager(); this.pathManager = new WalkPathDialogManager(this.registry);
this.pathManager.init(); this.pathManager.init();
} }

View File

@@ -3,6 +3,7 @@
* 负责管理漫游路径设置对话框的显示和交互 * 负责管理漫游路径设置对话框的显示和交互
*/ */
import { BaseDialogManager } from '../core/base-dialog-manager'; import { BaseDialogManager } from '../core/base-dialog-manager';
import { ManagerRegistry } from '../core/manager-registry';
import { WalkPathPanel } from '../components/walk-path-panel'; import { WalkPathPanel } from '../components/walk-path-panel';
/** /**
@@ -13,6 +14,10 @@ export class WalkPathDialogManager extends BaseDialogManager {
/** 漫游路径面板实例 */ /** 漫游路径面板实例 */
private panel: WalkPathPanel | null = null; private panel: WalkPathPanel | null = null;
constructor(registry: ManagerRegistry) {
super(registry);
}
/** 对话框唯一标识 */ /** 对话框唯一标识 */
protected get dialogId() { return 'walk-path-dialog'; } protected get dialogId() { return 'walk-path-dialog'; }
/** 对话框标题(国际化 key */ /** 对话框标题(国际化 key */
@@ -45,7 +50,7 @@ export class WalkPathDialogManager extends BaseDialogManager {
/** 创建对话框内容 */ /** 创建对话框内容 */
protected createContent(): HTMLElement { protected createContent(): HTMLElement {
this.panel = new WalkPathPanel(); this.panel = new WalkPathPanel(this.registry);
this.panel.init(); this.panel.init();
return this.panel.element; return this.panel.element;
} }

View File

@@ -3,6 +3,7 @@
* 负责管理漫游平面图对话框的显示和交互 * 负责管理漫游平面图对话框的显示和交互
*/ */
import { BaseDialogManager } from '../core/base-dialog-manager'; import { BaseDialogManager } from '../core/base-dialog-manager';
import { ManagerRegistry } from '../core/manager-registry';
import { WalkPlanViewPanel } from '../components/walk-plan-view-panel'; import { WalkPlanViewPanel } from '../components/walk-plan-view-panel';
/** /**
@@ -13,6 +14,10 @@ export class WalkPlanViewDialogManager extends BaseDialogManager {
/** 漫游平面图面板实例 */ /** 漫游平面图面板实例 */
private panel: WalkPlanViewPanel | null = null; private panel: WalkPlanViewPanel | null = null;
constructor(registry: ManagerRegistry) {
super(registry);
}
/** 对话框唯一标识 */ /** 对话框唯一标识 */
protected get dialogId() { return 'walk-plan-view-dialog'; } protected get dialogId() { return 'walk-plan-view-dialog'; }
/** 对话框标题(国际化 key */ /** 对话框标题(国际化 key */