2026-01-28 12:00:55 +08:00
|
|
|
|
# 构件详情右键菜单功能
|
|
|
|
|
|
|
|
|
|
|
|
## TL;DR
|
|
|
|
|
|
|
|
|
|
|
|
> **Quick Summary**: 实现右键菜单显示构件详情功能。用户选择构件后右键显示"构件详情"和"显示全部"菜单,点击构件详情弹出属性弹窗。
|
|
|
|
|
|
>
|
|
|
|
|
|
> **Deliverables**:
|
|
|
|
|
|
> - Engine 组件监听构件点击事件,记录选中构件信息
|
|
|
|
|
|
> - 修改右键菜单根据选中状态动态显示菜单项
|
|
|
|
|
|
> - 创建构件详情弹窗,调用底层 API 展示属性数据
|
|
|
|
|
|
>
|
|
|
|
|
|
> **Estimated Effort**: Medium
|
|
|
|
|
|
> **Parallel Execution**: NO - 顺序依赖
|
|
|
|
|
|
> **Critical Path**: Task 1 → Task 2 → Task 3 → Task 4 → Task 5 → Task 6
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Context
|
|
|
|
|
|
|
|
|
|
|
|
### Original Request
|
|
|
|
|
|
用户选择构件后,右键显示"构件详情"按钮(有选中时)或"显示全部"按钮(无选中时)。点击构件详情查询数据并弹窗展示。
|
|
|
|
|
|
|
|
|
|
|
|
### 底层 API 验证结果
|
|
|
|
|
|
|
|
|
|
|
|
#### 1. 构件属性查询 API ✅ 已验证
|
|
|
|
|
|
**文件**: `bim_engine_base/src/core/v2/managers/modelProperties/index.ts`
|
|
|
|
|
|
**实例化**: `EngineKernelV2.modelProperties`
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
// 调用方式
|
|
|
|
|
|
engine.modelProperties.getModelProperties(url: string, id: string, callback: (data) => void)
|
|
|
|
|
|
|
|
|
|
|
|
// 返回格式
|
|
|
|
|
|
{
|
|
|
|
|
|
properties: [{
|
|
|
|
|
|
name: string, // 分类名称
|
|
|
|
|
|
children: [{
|
|
|
|
|
|
name: string, // 属性名
|
|
|
|
|
|
value: any // 属性值
|
|
|
|
|
|
}]
|
|
|
|
|
|
}],
|
|
|
|
|
|
materials: []
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 2. 构件点击事件 ✅ 已验证
|
|
|
|
|
|
**文件**: `bim_engine_base/src/core/v2/modules/interactionModule.ts`
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
// 点击时触发
|
|
|
|
|
|
handleMouseClick(event) {
|
|
|
|
|
|
const hit = event.catch;
|
|
|
|
|
|
const model = hit.object;
|
|
|
|
|
|
// model.url → 模型URL
|
|
|
|
|
|
// model.name → 构件ID
|
|
|
|
|
|
engine.events.trigger(EventType.Click, hit);
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**EventType.Click** 数据结构:
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
{
|
|
|
|
|
|
point: Vector3, // 点击位置
|
|
|
|
|
|
object: {
|
|
|
|
|
|
url: string, // 模型URL
|
|
|
|
|
|
name: string // 构件ID
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 3. 右键菜单 API ✅ 已验证
|
|
|
|
|
|
**文件**: `engine/src/managers/right-key-manager.ts`
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
// 注册处理器
|
|
|
|
|
|
rightKey.registerHandler((e: MouseEvent) => MenuItemConfig[] | null)
|
|
|
|
|
|
|
|
|
|
|
|
// MenuItemConfig
|
|
|
|
|
|
interface MenuItemConfig {
|
|
|
|
|
|
id: string;
|
|
|
|
|
|
label: string;
|
|
|
|
|
|
onClick?: () => void;
|
|
|
|
|
|
icon?: string;
|
|
|
|
|
|
group?: string;
|
|
|
|
|
|
disabled?: boolean;
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Work Objectives
|
|
|
|
|
|
|
|
|
|
|
|
### Core Objective
|
|
|
|
|
|
实现构件详情右键菜单功能,包括:选中状态追踪、动态菜单、属性弹窗展示。
|
|
|
|
|
|
|
|
|
|
|
|
### Concrete Deliverables
|
|
|
|
|
|
- `engine/src/components/engine/index.ts` - 新增选中状态管理和事件监听
|
|
|
|
|
|
- `engine/src/managers/engine-manager.ts` - 暴露选中状态和属性查询方法,修改右键处理器
|
|
|
|
|
|
- `engine/src/managers/component-detail-manager.ts` - 新建构件详情弹窗管理器
|
|
|
|
|
|
- `engine/src/bim-engine.ts` - 注册新管理器
|
|
|
|
|
|
- `engine/src/locales/*.ts` - 新增国际化文本
|
|
|
|
|
|
- `.sisyphus/drafts/API_CALLCHAIN.md` - 重构调用链文档(从 Toolbar 专用扩展为全局文档)
|
|
|
|
|
|
|
|
|
|
|
|
### Definition of Done
|
2026-01-28 17:19:36 +08:00
|
|
|
|
- [x] `bun run build` 构建成功
|
|
|
|
|
|
- [x] 点击构件后,右键显示"构件详情"和"显示全部"
|
|
|
|
|
|
- [x] 未选中构件时,右键只显示"显示全部"
|
|
|
|
|
|
- [x] 点击"构件详情"弹出属性弹窗,展示底层 API 返回的数据
|
|
|
|
|
|
- [x] 点击"显示全部"控制台输出提示
|
|
|
|
|
|
- [x] 调用链文档已重构并更新
|
2026-01-28 12:00:55 +08:00
|
|
|
|
|
|
|
|
|
|
### Must Have
|
|
|
|
|
|
- 监听底层 Click 事件获取选中构件
|
|
|
|
|
|
- 根据选中状态动态返回菜单项
|
|
|
|
|
|
- 调用 `modelProperties.getModelProperties()` 获取属性
|
|
|
|
|
|
- 使用现有 Dialog + Collapse + Description 组件展示
|
|
|
|
|
|
|
|
|
|
|
|
### Must NOT Have (Guardrails)
|
|
|
|
|
|
- 不修改底层引擎代码(bim_engine_base)
|
|
|
|
|
|
- 不实现"显示全部"的实际逻辑(只 console.log)
|
|
|
|
|
|
- 不添加新的 npm 依赖
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Verification Strategy
|
|
|
|
|
|
|
|
|
|
|
|
### Test Decision
|
|
|
|
|
|
- **Infrastructure exists**: NO
|
|
|
|
|
|
- **User wants tests**: Manual-only
|
|
|
|
|
|
- **Framework**: none
|
|
|
|
|
|
|
|
|
|
|
|
### Manual QA
|
|
|
|
|
|
1. `bun run build` 无报错
|
|
|
|
|
|
2. 在 playground 中测试交互流程
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Task Flow
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
Task 1 (Engine 监听点击,记录选中)
|
|
|
|
|
|
↓
|
|
|
|
|
|
Task 2 (EngineManager 暴露方法,修改右键处理器)
|
|
|
|
|
|
↓
|
|
|
|
|
|
Task 3 (创建 ComponentDetailManager)
|
|
|
|
|
|
↓
|
|
|
|
|
|
Task 4 (BimEngine 注册管理器)
|
|
|
|
|
|
↓
|
|
|
|
|
|
Task 5 (国际化 + 构建验证)
|
|
|
|
|
|
↓
|
|
|
|
|
|
Task 6 (重构调用链文档)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## TODOs
|
|
|
|
|
|
|
2026-01-28 17:19:36 +08:00
|
|
|
|
- [x] 1. Engine 组件 - 监听构件点击,记录选中状态
|
2026-01-28 12:00:55 +08:00
|
|
|
|
|
|
|
|
|
|
**What to do**:
|
|
|
|
|
|
在 `engine/src/components/engine/index.ts` 中:
|
|
|
|
|
|
|
|
|
|
|
|
1. 新增私有属性存储选中构件信息:
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
private selectedComponent: { url: string; id: string } | null = null;
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
2. 在 `init()` 方法中监听底层 Click 事件:
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
this.engine.events.on('click', (hit: any) => {
|
|
|
|
|
|
if (hit && hit.object) {
|
|
|
|
|
|
this.selectedComponent = {
|
|
|
|
|
|
url: hit.object.url,
|
|
|
|
|
|
id: hit.object.name
|
|
|
|
|
|
};
|
|
|
|
|
|
console.log('[Engine] 构件选中:', this.selectedComponent);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.selectedComponent = null;
|
|
|
|
|
|
console.log('[Engine] 取消选中');
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
3. 新增公共方法:
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
public getSelectedComponent(): { url: string; id: string } | null {
|
|
|
|
|
|
return this.selectedComponent;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public getComponentProperties(
|
|
|
|
|
|
url: string,
|
|
|
|
|
|
id: string,
|
|
|
|
|
|
callback: (data: any) => void
|
|
|
|
|
|
): void {
|
|
|
|
|
|
if (!this.engine?.modelProperties) {
|
|
|
|
|
|
console.error('[Engine] modelProperties not available');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
this.engine.modelProperties.getModelProperties(url, id, callback);
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Must NOT do**:
|
|
|
|
|
|
- 不要修改现有的其他功能
|
|
|
|
|
|
|
|
|
|
|
|
**Parallelizable**: NO (后续任务依赖)
|
|
|
|
|
|
|
|
|
|
|
|
**References**:
|
|
|
|
|
|
- `bim_engine_base/src/core/v2/modules/interactionModule.ts:36-53` - Click 事件触发逻辑
|
|
|
|
|
|
- `bim_engine_base/src/core/v2/managers/modelProperties/index.ts:11-52` - getModelProperties 实现
|
|
|
|
|
|
- `engine/src/components/engine/index.ts:108-131` - init() 方法位置
|
|
|
|
|
|
|
|
|
|
|
|
**Acceptance Criteria**:
|
2026-01-28 17:19:36 +08:00
|
|
|
|
- [x] 新增 `selectedComponent` 私有属性
|
|
|
|
|
|
- [x] 在 init() 中监听 click 事件
|
|
|
|
|
|
- [x] 新增 `getSelectedComponent()` 方法
|
|
|
|
|
|
- [x] 新增 `getComponentProperties()` 方法
|
|
|
|
|
|
- [x] 点击构件时控制台输出选中信息
|
2026-01-28 12:00:55 +08:00
|
|
|
|
|
|
|
|
|
|
**Commit**: YES
|
|
|
|
|
|
- Message: `feat(engine): 监听构件点击事件并记录选中状态`
|
|
|
|
|
|
- Files: `src/components/engine/index.ts`
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-01-28 17:19:36 +08:00
|
|
|
|
- [x] 2. EngineManager - 暴露方法并修改右键处理器
|
2026-01-28 12:00:55 +08:00
|
|
|
|
|
|
|
|
|
|
**What to do**:
|
|
|
|
|
|
在 `engine/src/managers/engine-manager.ts` 中:
|
|
|
|
|
|
|
|
|
|
|
|
1. 新增代理方法:
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
public getSelectedComponent(): { url: string; id: string } | null {
|
|
|
|
|
|
return this.engineInstance?.getSelectedComponent() ?? null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public getComponentProperties(
|
|
|
|
|
|
url: string,
|
|
|
|
|
|
id: string,
|
|
|
|
|
|
callback: (data: any) => void
|
|
|
|
|
|
): void {
|
|
|
|
|
|
this.engineInstance?.getComponentProperties(url, id, callback);
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
2. 修改 `initialize()` 中的 `registerHandler`,根据选中状态返回不同菜单:
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
this.rightKey.registerHandler((_e) => {
|
|
|
|
|
|
const selected = this.getSelectedComponent();
|
|
|
|
|
|
const items: MenuItemConfig[] = [];
|
|
|
|
|
|
|
|
|
|
|
|
if (selected) {
|
|
|
|
|
|
items.push({
|
|
|
|
|
|
id: 'componentDetail',
|
|
|
|
|
|
label: 'menu.componentDetail',
|
|
|
|
|
|
group: 'component',
|
|
|
|
|
|
onClick: () => {
|
|
|
|
|
|
const registry = ManagerRegistry.getInstance();
|
|
|
|
|
|
registry.componentDetail?.show(selected.url, selected.id);
|
|
|
|
|
|
this.rightKey?.hide();
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
items.push({
|
|
|
|
|
|
id: 'showAll',
|
|
|
|
|
|
label: 'menu.showAll',
|
|
|
|
|
|
group: 'component',
|
|
|
|
|
|
onClick: () => {
|
|
|
|
|
|
console.log('[Menu] 显示全部 - 功能开发中');
|
|
|
|
|
|
this.rightKey?.hide();
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
items.push(infoMenuButton());
|
|
|
|
|
|
items.push(homeMenuButton());
|
|
|
|
|
|
|
|
|
|
|
|
return items;
|
|
|
|
|
|
});
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Must NOT do**:
|
|
|
|
|
|
- 不要删除现有的 infoMenuButton 和 homeMenuButton
|
|
|
|
|
|
|
|
|
|
|
|
**Parallelizable**: NO (依赖 Task 1)
|
|
|
|
|
|
|
|
|
|
|
|
**References**:
|
|
|
|
|
|
- `engine/src/managers/engine-manager.ts:50-57` - 现有 registerHandler 位置
|
|
|
|
|
|
- `engine/src/components/menu/item.ts` - MenuItemConfig 定义
|
|
|
|
|
|
|
|
|
|
|
|
**Acceptance Criteria**:
|
2026-01-28 17:19:36 +08:00
|
|
|
|
- [x] 新增 `getSelectedComponent()` 代理方法
|
|
|
|
|
|
- [x] 新增 `getComponentProperties()` 代理方法
|
|
|
|
|
|
- [x] 修改 registerHandler 动态返回菜单项
|
|
|
|
|
|
- [x] 有选中时显示"构件详情"+"显示全部"
|
|
|
|
|
|
- [x] 无选中时只显示"显示全部"
|
2026-01-28 12:00:55 +08:00
|
|
|
|
|
|
|
|
|
|
**Commit**: YES
|
|
|
|
|
|
- Message: `feat(engine-manager): 添加构件选中方法和动态右键菜单`
|
|
|
|
|
|
- Files: `src/managers/engine-manager.ts`
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-01-28 17:19:36 +08:00
|
|
|
|
- [x] 3. 创建 ComponentDetailManager - 构件详情弹窗
|
2026-01-28 12:00:55 +08:00
|
|
|
|
|
|
|
|
|
|
**What to do**:
|
|
|
|
|
|
创建 `engine/src/managers/component-detail-manager.ts`:
|
|
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
import { BaseManager } from '../core/base-manager';
|
|
|
|
|
|
import { BimCollapse } from '../components/collapse/index';
|
|
|
|
|
|
import { BimDescription } from '../components/description/index';
|
|
|
|
|
|
|
|
|
|
|
|
export class ComponentDetailManager extends BaseManager {
|
|
|
|
|
|
private dialogId = 'component-detail-dialog';
|
|
|
|
|
|
private dialog: any = null;
|
|
|
|
|
|
|
|
|
|
|
|
constructor() {
|
|
|
|
|
|
super();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public show(modelUrl: string, componentId: string): void {
|
|
|
|
|
|
if (!this.registry.dialog) {
|
|
|
|
|
|
console.warn('[ComponentDetailManager] Dialog manager not initialized');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (this.isOpen()) {
|
|
|
|
|
|
this.hide();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 先创建弹窗显示加载中
|
|
|
|
|
|
this.createDialog();
|
|
|
|
|
|
this.showLoading();
|
|
|
|
|
|
|
|
|
|
|
|
// 调用底层 API 获取属性
|
|
|
|
|
|
this.registry.engine3d?.getComponentProperties(modelUrl, componentId, (data) => {
|
|
|
|
|
|
this.renderProperties(data, componentId);
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private createDialog(): void {
|
|
|
|
|
|
const width = 400;
|
|
|
|
|
|
const x = document.body.clientWidth - width - 40;
|
|
|
|
|
|
|
|
|
|
|
|
this.dialog = this.registry.dialog.create({
|
|
|
|
|
|
id: this.dialogId,
|
|
|
|
|
|
title: 'panel.componentDetail.title',
|
|
|
|
|
|
content: '',
|
|
|
|
|
|
width: `${width}px`,
|
|
|
|
|
|
height: '500px',
|
|
|
|
|
|
position: { x, y: 20 },
|
|
|
|
|
|
showMask: false,
|
|
|
|
|
|
resizable: true,
|
|
|
|
|
|
onClose: () => this.hide()
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private showLoading(): void {
|
|
|
|
|
|
const container = document.createElement('div');
|
|
|
|
|
|
container.style.padding = '20px';
|
|
|
|
|
|
container.style.textAlign = 'center';
|
|
|
|
|
|
container.textContent = '加载中...';
|
|
|
|
|
|
this.dialog?.setContent(container);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private renderProperties(data: any, componentId: string): void {
|
|
|
|
|
|
if (!this.dialog) return;
|
|
|
|
|
|
|
|
|
|
|
|
const container = document.createElement('div');
|
|
|
|
|
|
container.style.height = '100%';
|
|
|
|
|
|
container.style.overflowY = 'auto';
|
|
|
|
|
|
|
|
|
|
|
|
const properties = data?.properties || [];
|
|
|
|
|
|
|
|
|
|
|
|
if (properties.length === 0) {
|
|
|
|
|
|
container.innerHTML = '<div style="padding:20px;text-align:center;">无属性数据</div>';
|
|
|
|
|
|
this.dialog.setContent(container);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 转换为 Collapse 需要的格式
|
|
|
|
|
|
const collapseItems = properties.map((category: any, index: number) => ({
|
|
|
|
|
|
id: `category-${index}`,
|
|
|
|
|
|
title: category.name || `分类 ${index + 1}`,
|
|
|
|
|
|
content: this.createCategoryContent(category.children || [])
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
|
|
new BimCollapse({
|
|
|
|
|
|
container,
|
|
|
|
|
|
accordion: false,
|
|
|
|
|
|
activeIds: collapseItems.length > 0 ? [collapseItems[0].id] : [],
|
|
|
|
|
|
items: collapseItems
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
this.dialog.setContent(container);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private createCategoryContent(items: any[]): HTMLElement {
|
|
|
|
|
|
const container = document.createElement('div');
|
|
|
|
|
|
|
|
|
|
|
|
const descItems = items.map((item: any) => ({
|
|
|
|
|
|
label: item.name || '-',
|
|
|
|
|
|
value: String(item.value ?? '-')
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
|
|
new BimDescription({
|
|
|
|
|
|
container,
|
|
|
|
|
|
labelWidth: '120px',
|
|
|
|
|
|
bordered: true,
|
|
|
|
|
|
items: descItems
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
return container;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public isOpen(): boolean {
|
|
|
|
|
|
return this.dialog !== null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public hide(): void {
|
|
|
|
|
|
if (this.dialog) {
|
|
|
|
|
|
this.dialog.destroy();
|
|
|
|
|
|
this.dialog = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public destroy(): void {
|
|
|
|
|
|
this.hide();
|
|
|
|
|
|
super.destroy();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Must NOT do**:
|
|
|
|
|
|
- 不要创建新的 UI 组件,复用现有的 Collapse/Description
|
|
|
|
|
|
|
|
|
|
|
|
**Parallelizable**: NO (依赖 Task 2)
|
|
|
|
|
|
|
|
|
|
|
|
**References**:
|
|
|
|
|
|
- `engine/src/managers/property-panel-manager.ts` - 参考现有属性面板实现
|
|
|
|
|
|
- `engine/src/components/collapse/index.ts` - Collapse 组件
|
|
|
|
|
|
- `engine/src/components/description/index.ts` - Description 组件
|
|
|
|
|
|
|
|
|
|
|
|
**Acceptance Criteria**:
|
2026-01-28 17:19:36 +08:00
|
|
|
|
- [x] 新建 `component-detail-manager.ts` 文件
|
|
|
|
|
|
- [x] 实现 `show(modelUrl, componentId)` 方法
|
|
|
|
|
|
- [x] 调用底层 API 获取属性数据
|
|
|
|
|
|
- [x] 使用 Collapse + Description 展示属性
|
|
|
|
|
|
- [x] 实现 `hide()` 和 `destroy()` 方法
|
2026-01-28 12:00:55 +08:00
|
|
|
|
|
|
|
|
|
|
**Commit**: YES
|
|
|
|
|
|
- Message: `feat: 新增构件详情弹窗管理器`
|
|
|
|
|
|
- Files: `src/managers/component-detail-manager.ts`
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-01-28 17:19:36 +08:00
|
|
|
|
- [x] 4. BimEngine 和 Registry 注册管理器
|
2026-01-28 12:00:55 +08:00
|
|
|
|
|
|
|
|
|
|
**What to do**:
|
|
|
|
|
|
|
|
|
|
|
|
1. 修改 `engine/src/core/manager-registry.ts`,添加类型声明:
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
import type { ComponentDetailManager } from '../managers/component-detail-manager';
|
|
|
|
|
|
|
|
|
|
|
|
// 在 ManagerRegistry 类中添加
|
|
|
|
|
|
public componentDetail: ComponentDetailManager | null = null;
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
2. 修改 `engine/src/bim-engine.ts`,添加初始化方法:
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
import { ComponentDetailManager } from './managers/component-detail-manager';
|
|
|
|
|
|
|
|
|
|
|
|
// 添加属性
|
|
|
|
|
|
public componentDetail: ComponentDetailManager | null = null;
|
|
|
|
|
|
|
|
|
|
|
|
// 添加初始化方法
|
|
|
|
|
|
public initComponentDetail(): void {
|
|
|
|
|
|
this.componentDetail = new ComponentDetailManager();
|
|
|
|
|
|
this.registry.componentDetail = this.componentDetail;
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Must NOT do**:
|
|
|
|
|
|
- 不要修改其他管理器的初始化逻辑
|
|
|
|
|
|
|
|
|
|
|
|
**Parallelizable**: NO (依赖 Task 3)
|
|
|
|
|
|
|
|
|
|
|
|
**References**:
|
|
|
|
|
|
- `engine/src/bim-engine.ts:106-108` - PropertyPanelManager 注册方式
|
|
|
|
|
|
- `engine/src/core/manager-registry.ts` - Registry 结构
|
|
|
|
|
|
|
|
|
|
|
|
**Acceptance Criteria**:
|
2026-01-28 17:19:36 +08:00
|
|
|
|
- [x] ManagerRegistry 添加 componentDetail 类型声明
|
|
|
|
|
|
- [x] BimEngine 添加 componentDetail 属性
|
|
|
|
|
|
- [x] BimEngine 添加 initComponentDetail() 方法
|
2026-01-28 12:00:55 +08:00
|
|
|
|
|
|
|
|
|
|
**Commit**: YES
|
|
|
|
|
|
- Message: `feat(bim-engine): 注册构件详情管理器`
|
|
|
|
|
|
- Files: `src/bim-engine.ts`, `src/core/manager-registry.ts`
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-01-28 17:19:36 +08:00
|
|
|
|
- [x] 5. 国际化文本 + 构建验证
|
2026-01-28 12:00:55 +08:00
|
|
|
|
|
|
|
|
|
|
**What to do**:
|
|
|
|
|
|
|
|
|
|
|
|
1. 修改 `engine/src/locales/zh-CN.ts`,添加:
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
menu: {
|
|
|
|
|
|
// 现有...
|
|
|
|
|
|
componentDetail: '构件详情',
|
|
|
|
|
|
showAll: '显示全部',
|
|
|
|
|
|
},
|
|
|
|
|
|
panel: {
|
|
|
|
|
|
// 现有...
|
|
|
|
|
|
componentDetail: {
|
|
|
|
|
|
title: '构件详情',
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
2. 修改 `engine/src/locales/en-US.ts`,添加:
|
|
|
|
|
|
```typescript
|
|
|
|
|
|
menu: {
|
|
|
|
|
|
// 现有...
|
|
|
|
|
|
componentDetail: 'Component Detail',
|
|
|
|
|
|
showAll: 'Show All',
|
|
|
|
|
|
},
|
|
|
|
|
|
panel: {
|
|
|
|
|
|
// 现有...
|
|
|
|
|
|
componentDetail: {
|
|
|
|
|
|
title: 'Component Detail',
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
3. 运行构建验证:
|
|
|
|
|
|
```bash
|
|
|
|
|
|
bun run build
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Must NOT do**:
|
|
|
|
|
|
- 不要修改现有的国际化文本
|
|
|
|
|
|
|
|
|
|
|
|
**Parallelizable**: NO (依赖前面所有任务)
|
|
|
|
|
|
|
|
|
|
|
|
**References**:
|
|
|
|
|
|
- `engine/src/locales/zh-CN.ts` - 中文国际化
|
|
|
|
|
|
- `engine/src/locales/en-US.ts` - 英文国际化
|
|
|
|
|
|
|
|
|
|
|
|
**Acceptance Criteria**:
|
2026-01-28 17:19:36 +08:00
|
|
|
|
- [x] zh-CN 添加 menu.componentDetail, menu.showAll, panel.componentDetail.title
|
|
|
|
|
|
- [x] en-US 添加对应英文文本
|
|
|
|
|
|
- [x] `bun run build` 执行成功,无报错
|
2026-01-28 12:00:55 +08:00
|
|
|
|
|
|
|
|
|
|
**Commit**: YES
|
|
|
|
|
|
- Message: `feat(i18n): 添加构件详情相关国际化文本`
|
|
|
|
|
|
- Files: `src/locales/zh-CN.ts`, `src/locales/en-US.ts`
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-01-28 17:19:36 +08:00
|
|
|
|
- [x] 6. 重构调用链文档
|
2026-01-28 12:00:55 +08:00
|
|
|
|
|
|
|
|
|
|
**What to do**:
|
|
|
|
|
|
|
|
|
|
|
|
1. 将 `.sisyphus/drafts/TOOLBAR_API_CALLCHAIN.md` 重命名为 `.sisyphus/drafts/API_CALLCHAIN.md`
|
|
|
|
|
|
|
|
|
|
|
|
2. 重构文档结构,从 Toolbar 专用扩展为全局 API 调用链文档:
|
|
|
|
|
|
|
|
|
|
|
|
```markdown
|
|
|
|
|
|
# SDK API 调用链文档
|
|
|
|
|
|
|
|
|
|
|
|
本文档记录 SDK 中所有功能的完整调用链,从用户交互到底层 3D 引擎 API。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 目录
|
|
|
|
|
|
|
|
|
|
|
|
1. [Toolbar 工具栏](#1-toolbar-工具栏)
|
|
|
|
|
|
2. [右键菜单 (Context Menu)](#2-右键菜单-context-menu)
|
|
|
|
|
|
3. [构件交互 (Component Interaction)](#3-构件交互-component-interaction)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 1. Toolbar 工具栏
|
|
|
|
|
|
|
|
|
|
|
|
### 1.1 首页 (Home)
|
|
|
|
|
|
[原有内容...]
|
|
|
|
|
|
|
|
|
|
|
|
### 1.2 框选放大 (Zoom Box)
|
|
|
|
|
|
[原有内容...]
|
|
|
|
|
|
|
|
|
|
|
|
...(其他 toolbar 按钮)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 2. 右键菜单 (Context Menu)
|
|
|
|
|
|
|
|
|
|
|
|
### 2.1 构件详情 (Component Detail)
|
|
|
|
|
|
|
|
|
|
|
|
**触发条件**: 选中构件后右键
|
|
|
|
|
|
**功能**: 查询并展示构件属性
|
|
|
|
|
|
|
|
|
|
|
|
#### 调用链
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
用户点击构件
|
|
|
|
|
|
│
|
|
|
|
|
|
▼
|
|
|
|
|
|
底层 interactionModule.handleMouseClick()
|
|
|
|
|
|
│ engine.events.trigger('click', hit)
|
|
|
|
|
|
▼
|
|
|
|
|
|
[SDK] Engine 监听 'click' 事件
|
|
|
|
|
|
│ 记录 selectedComponent = { url, id }
|
|
|
|
|
|
▼
|
|
|
|
|
|
用户右键点击
|
|
|
|
|
|
│
|
|
|
|
|
|
▼
|
|
|
|
|
|
[SDK] RightKeyManager.handleContextMenu()
|
|
|
|
|
|
│ 调用所有 contextHandlers
|
|
|
|
|
|
▼
|
|
|
|
|
|
[SDK] EngineManager 的 handler
|
|
|
|
|
|
│ 检查 getSelectedComponent()
|
|
|
|
|
|
│ 返回 MenuItemConfig[] (含 "构件详情")
|
|
|
|
|
|
▼
|
|
|
|
|
|
用户点击 "构件详情"
|
|
|
|
|
|
│
|
|
|
|
|
|
▼
|
|
|
|
|
|
[SDK] ComponentDetailManager.show(url, id)
|
|
|
|
|
|
│ 调用 getComponentProperties(url, id, callback)
|
|
|
|
|
|
▼
|
|
|
|
|
|
[SDK] Engine.getComponentProperties()
|
|
|
|
|
|
│ this.engine.modelProperties.getModelProperties(url, id, callback)
|
|
|
|
|
|
▼
|
|
|
|
|
|
[底层] ModelProperties.getModelProperties()
|
|
|
|
|
|
│ 加载/解析属性数据
|
|
|
|
|
|
▼
|
|
|
|
|
|
[SDK] ComponentDetailManager.renderProperties()
|
|
|
|
|
|
│ 展示属性弹窗
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 2.2 显示全部 (Show All)
|
|
|
|
|
|
|
|
|
|
|
|
**触发条件**: 右键(无论是否选中)
|
|
|
|
|
|
**功能**: 显示全部构件(暂未实现)
|
|
|
|
|
|
|
|
|
|
|
|
#### 调用链
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
用户右键点击
|
|
|
|
|
|
│
|
|
|
|
|
|
▼
|
|
|
|
|
|
[SDK] RightKeyManager.handleContextMenu()
|
|
|
|
|
|
│
|
|
|
|
|
|
▼
|
|
|
|
|
|
[SDK] EngineManager 的 handler
|
|
|
|
|
|
│ 返回 MenuItemConfig[] (含 "显示全部")
|
|
|
|
|
|
▼
|
|
|
|
|
|
用户点击 "显示全部"
|
|
|
|
|
|
│
|
|
|
|
|
|
▼
|
|
|
|
|
|
console.log('显示全部 - 功能开发中')
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 2.3 信息 (Info)
|
|
|
|
|
|
[现有 infoMenuButton 的调用链]
|
|
|
|
|
|
|
|
|
|
|
|
### 2.4 首页 (Home)
|
|
|
|
|
|
[现有 homeMenuButton 的调用链]
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 3. 构件交互 (Component Interaction)
|
|
|
|
|
|
|
|
|
|
|
|
### 3.1 构件选中
|
|
|
|
|
|
|
|
|
|
|
|
**触发条件**: 点击 3D 场景中的构件
|
|
|
|
|
|
**功能**: 高亮构件并记录选中状态
|
|
|
|
|
|
|
|
|
|
|
|
#### 调用链
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
用户点击 3D 场景
|
|
|
|
|
|
│
|
|
|
|
|
|
▼
|
|
|
|
|
|
[底层] handelBehaved 监听 mouseup
|
|
|
|
|
|
│ 射线检测 (raycaster)
|
|
|
|
|
|
▼
|
|
|
|
|
|
[底层] interactionModule.handleMouseClick(event)
|
|
|
|
|
|
│ event.catch = 射线检测结果
|
|
|
|
|
|
│ engine.events.trigger('click', hit)
|
|
|
|
|
|
│ engine.modelToolModule.highlightModel([{url, ids}])
|
|
|
|
|
|
▼
|
|
|
|
|
|
[SDK] Engine 监听 'click' 事件
|
|
|
|
|
|
│ 记录 this.selectedComponent = { url: hit.object.url, id: hit.object.name }
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 3.2 取消选中
|
|
|
|
|
|
|
|
|
|
|
|
**触发条件**: 点击空白区域
|
|
|
|
|
|
**功能**: 取消高亮并清除选中状态
|
|
|
|
|
|
|
|
|
|
|
|
#### 调用链
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
用户点击空白区域
|
|
|
|
|
|
│
|
|
|
|
|
|
▼
|
|
|
|
|
|
[底层] interactionModule.handleMouseClick(event)
|
|
|
|
|
|
│ event.catch = null
|
|
|
|
|
|
│ engine.modelToolModule.unhighlightAllModels()
|
|
|
|
|
|
▼
|
|
|
|
|
|
[SDK] Engine 监听 'click' 事件
|
|
|
|
|
|
│ this.selectedComponent = null
|
|
|
|
|
|
```
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Must NOT do**:
|
|
|
|
|
|
- 不要删除现有 Toolbar 部分的内容
|
|
|
|
|
|
- 不要修改现有调用链的准确性
|
|
|
|
|
|
|
|
|
|
|
|
**Parallelizable**: NO (依赖 Task 5)
|
|
|
|
|
|
|
|
|
|
|
|
**References**:
|
|
|
|
|
|
- `.sisyphus/drafts/TOOLBAR_API_CALLCHAIN.md` - 现有文档
|
|
|
|
|
|
- `engine/src/managers/right-key-manager.ts` - 右键菜单实现
|
|
|
|
|
|
- `engine/src/managers/engine-manager.ts` - 右键处理器注册
|
|
|
|
|
|
|
|
|
|
|
|
**Acceptance Criteria**:
|
2026-01-28 17:19:36 +08:00
|
|
|
|
- [x] 文档重命名为 `API_CALLCHAIN.md`
|
|
|
|
|
|
- [x] 文档标题改为"SDK API 调用链文档"
|
|
|
|
|
|
- [x] 新增"右键菜单"章节,包含构件详情、显示全部、信息、首页
|
|
|
|
|
|
- [x] 新增"构件交互"章节,包含选中/取消选中调用链
|
|
|
|
|
|
- [x] 原 Toolbar 内容保持不变,作为第一章
|
2026-01-28 12:00:55 +08:00
|
|
|
|
|
|
|
|
|
|
**Commit**: YES
|
|
|
|
|
|
- Message: `docs: 重构调用链文档,新增右键菜单和构件交互章节`
|
|
|
|
|
|
- Files: `.sisyphus/drafts/API_CALLCHAIN.md`
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Commit Strategy
|
|
|
|
|
|
|
|
|
|
|
|
| After Task | Message | Files |
|
|
|
|
|
|
|------------|---------|-------|
|
|
|
|
|
|
| 1 | `feat(engine): 监听构件点击事件并记录选中状态` | src/components/engine/index.ts |
|
|
|
|
|
|
| 2 | `feat(engine-manager): 添加构件选中方法和动态右键菜单` | src/managers/engine-manager.ts |
|
|
|
|
|
|
| 3 | `feat: 新增构件详情弹窗管理器` | src/managers/component-detail-manager.ts |
|
|
|
|
|
|
| 4 | `feat(bim-engine): 注册构件详情管理器` | src/bim-engine.ts, src/core/manager-registry.ts |
|
|
|
|
|
|
| 5 | `feat(i18n): 添加构件详情相关国际化文本` | src/locales/*.ts |
|
|
|
|
|
|
| 6 | `docs: 重构调用链文档,新增右键菜单和构件交互章节` | .sisyphus/drafts/API_CALLCHAIN.md |
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Success Criteria
|
|
|
|
|
|
|
|
|
|
|
|
### Verification Commands
|
|
|
|
|
|
```bash
|
|
|
|
|
|
bun run build # Expected: BUILD SUCCESS
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Final Checklist
|
2026-01-28 17:19:36 +08:00
|
|
|
|
- [x] 点击构件后,控制台输出选中信息
|
|
|
|
|
|
- [x] 有选中构件时,右键显示"构件详情"+"显示全部"
|
|
|
|
|
|
- [x] 无选中构件时,右键只显示"显示全部"
|
|
|
|
|
|
- [x] 点击"构件详情"弹出属性弹窗
|
|
|
|
|
|
- [x] 弹窗正确展示底层 API 返回的属性数据
|
|
|
|
|
|
- [x] 点击"显示全部"控制台输出提示
|
|
|
|
|
|
- [x] 构建成功
|
|
|
|
|
|
- [x] 调用链文档已重构为全局文档
|
|
|
|
|
|
- [x] 新增右键菜单章节
|
|
|
|
|
|
- [x] 新增构件交互章节
|