Files
bim_engine/AI_COLLABORATION.md

1345 lines
43 KiB
Markdown
Raw Normal View History

2025-12-08 10:02:24 +08:00
# BIM Engine SDK - AI 协作文档
> 本文档用于向 AI 助手传递项目信息,帮助 AI 更好地理解和维护本项目。**每次代码改动后,请务必更新本文档的相关部分。**
---
## 📋 目录
1. [项目基本信息](#1-项目基本信息)
2. [架构设计思想](#2-架构设计思想)
3. [文件结构说明](#3-文件结构说明)
4. [组件和事件清单](#4-组件和事件清单)
5. [AI 工作规则](#5-ai-工作规则)
---
## 1. 项目基本信息
### 1.1 项目描述
**BIM Engine SDK** 是一个通用的 3D BIM 引擎 SDK 开发框架,旨在通过一次编码,同时支持 Vue 2、Vue 3、React 和纯 HTML 环境。
### 1.2 技术栈
- **语言**: TypeScript
- **构建工具**: Vite (Library Mode)
- **类型生成**: vite-plugin-dts
- **CSS 注入**: vite-plugin-css-injected-by-js
- **3D 引擎**: 基于第三方 SDK (bim-engine-sdk.es.js)
### 1.3 项目结构
```
engine/
├── src/ # SDK 源代码
│ ├── core/ # 核心基础类
│ ├── components/ # UI 组件
│ ├── managers/ # 管理器类
│ ├── services/ # 服务类(主题、语言)
│ ├── themes/ # 主题配置
│ ├── locales/ # 国际化配置
│ ├── types/ # 类型定义
│ ├── bim-engine.ts # 主引擎类
│ └── index.ts # 入口文件
├── dist/ # 构建产物 (ESM + UMD + .d.ts)
├── demo/ # HTML 示例
├── demo-vue/ # Vue 示例
├── docs/ # 文档目录
│ └── components/ # 组件详细文档(每个组件一份)
├── .recycle/ # 回收文件夹(按日期 YYYY-MM-DD 组织,存放被删除的文件)
├── vite.config.ts # Vite 构建配置
├── tsconfig.json # TypeScript 配置
└── package.json # 项目元数据
```
### 1.4 构建和运行
#### 构建 SDK
```bash
npm run build
# 生成 dist/ 目录,包含:
# - bim-engine-sdk.es.js (ESM 格式)
# - bim-engine-sdk.umd.js (UMD 格式)
# - index.d.ts (TypeScript 类型定义)
# - *.map (Source Map 文件)
```
#### 运行 Demo
**运行 HTML Demo (纯 JS):**
```bash
npm run dev:demo
# 自动执行:构建 SDK -> 复制 SDK 到 demo/lib -> 启动服务器
2025-12-08 10:02:24 +08:00
# 开发服务器运行在 http://localhost:3000
# 自动打开 /demo/index.html
```
**运行 Vue Demo:**
```bash
npm run dev:demo-vue
# 自动执行:构建 SDK -> 复制 SDK 到 demo-vue/public/lib -> 启动服务器
2025-12-08 10:02:24 +08:00
# 开发服务器运行在 http://localhost:3000
# 自动打开 Vue 示例页面
```
**同时运行两个 Demo:**
```bash
npm run dev:all
# 同时启动 HTML Demo 和 Vue Demo
```
**注意**:
- 现在的 `npm run dev:demo``npm run dev:demo-vue` 命令已包含自动化构建流程,无需手动运行 `npm run build`
- Demo 会自动从本地复制的 SDK 副本加载。
2025-12-08 10:02:24 +08:00
### 1.5 发布配置
`package.json` 配置了 `exports` 字段,确保不同环境自动加载正确的文件:
```json
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/bim-engine-sdk.es.js",
"require": "./dist/bim-engine-sdk.umd.js"
}
}
```
---
## 2. 架构设计思想
### 2.1 核心架构模式
#### Manager 模式
项目采用 **Manager 模式** 来管理不同类型的组件:
- **BimEngine**: 总控制器,组合各个 Manager
- **DialogManager**: 管理所有弹窗实例
- **ToolbarManager**: 管理底部工具栏
- **ButtonGroupManager**: 管理通用按钮组
- **EngineManager**: 管理 3D 引擎(延迟初始化)
#### 事件总线模式
项目采用 **混合通信模式**,根据场景选择最合适的方式:
- **BimEngine** 继承 `EventEmitter`,作为全局事件总线
- **BimComponent** 基类提供 `emit()``on()` 辅助方法
- 所有 Manager 继承 `BimComponent`,可方便地发送和监听事件
- 事件类型通过 `EngineEvents` 接口进行类型约束
**使用场景选择原则**
1. **简单场景 → 直接调用方法**
- 一对一调用,调用链简单
- 需要立即得到返回值
- 性能要求高的场景
- **示例**
```typescript
// 直接调用 Manager 方法
engine.dialog.create({ title: '测试' });
engine.toolbar.addButton({ id: 'btn1', ... });
```
2. **复杂场景 → 使用事件总线(发布订阅)**
- 需要多个组件监听同一事件(一对多)
- 调用链复杂,需要跨多层传递
- 需要解耦,降低组件间依赖
- 异步通知场景
- **示例**
```typescript
// 发送事件,多个组件可以监听
this.emit('ui:open-dialog', { id: 'info' });
// 多个组件可以同时监听
this.on('engine:model-loaded', (payload) => {
// 处理模型加载完成
});
```
#### 依赖注入模式
**EngineManager** 采用依赖注入模式,不直接依赖具体的 3D 引擎实现:
- `Engine` 组件通过参数接收 `createEngine` 函数
- 可以在运行时决定使用哪个引擎实现
- 便于测试和切换不同的 3D 引擎
### 2.2 组件设计原则
#### IBimComponent 接口
所有 UI 组件必须实现 `IBimComponent` 接口:
```typescript
interface IBimComponent {
init(): void | Promise<void>; // 初始化组件
setTheme(theme: ThemeConfig): void; // 设置主题
setLocales(): void; // 设置语言
destroy(): void; // 销毁组件
}
```
#### BimComponent 基类
所有 Manager 类继承 `BimComponent` 基类:
- 自动注入 `BimEngine` 实例
- 提供 `emit()``on()` 方法访问事件总线
- 必须实现 `destroy()` 方法
#### 组件生命周期
1. **构造阶段**: 创建实例,设置配置
2. **初始化阶段**: 调用 `init()` 创建 DOM、绑定事件
3. **运行阶段**: 响应主题/语言变更,处理用户交互
4. **销毁阶段**: 调用 `destroy()` 清理资源
### 2.3 代码组织规范
#### 目录结构约定
- `core/`: 核心基础类EventEmitter、BimComponent
- `components/`: UI 组件Dialog、ButtonGroup、Engine
- `managers/`: 管理器类(统一管理组件实例)
- `services/`: 服务类(单例模式,如 ThemeManager、LocaleManager
- `themes/`: 主题配置(预设主题和类型定义)
- `locales/`: 国际化配置(多语言翻译)
- `types/`: 类型定义(接口、类型别名)
#### 命名规范
- **类名**: 大驼峰,如 `BimDialog``DialogManager`
- **接口名**: 大驼峰,以 `I` 开头表示接口,如 `IBimComponent`
- **类型名**: 大驼峰,如 `ThemeConfig``DialogOptions`
- **文件名**: 小写短横线或直接小写,如 `event-emitter.ts``index.ts`
- **CSS 类名**: 小写短横线,以 `bim-` 开头,如 `bim-dialog``bim-btn-group`
#### 导入顺序
1. 第三方库
2. 项目内部类型定义
3. 项目内部组件/类
4. 项目内部服务/工具
5. CSS 文件(使用 `import './index.css'`
### 2.4 重要设计决策
#### 延迟初始化
- **3D 引擎**: 采用延迟初始化,用户需主动调用 `initEngine()` 方法
- **原因**: 3D 引擎资源消耗大,延迟初始化可以优化性能
#### 单例服务
- **ThemeManager**: 全局单例,所有组件共享同一主题状态
- **LocaleManager**: 全局单例,所有组件共享同一语言状态
- **原因**: 主题和语言是全局状态,单例模式确保一致性
#### CSS 变量
- 组件使用 CSS 变量来应用主题颜色
- 主题变更时,只需更新 CSS 变量值
- **优势**: 性能好,无需重新渲染 DOM
#### 事件拦截
- Dialog 组件会拦截所有鼠标/触摸事件,防止传递给 3D 引擎
- 使用 `stopPropagation()` 阻止事件冒泡
- **原因**: 确保弹窗交互不影响 3D 场景操作
---
## 3. 文件结构说明
### 3.1 核心文件 (`src/core/`)
#### `event-emitter.ts`
- **作用**: 事件总线基础类
- **功能**:
- `on(event, listener)`: 订阅事件
- `off(event, listener)`: 取消订阅
- `emit(event, payload)`: 发送事件
- `clear()`: 清空所有事件监听
- **使用**: `BimEngine` 继承此类,作为全局事件总线
#### `component.ts`
- **作用**: 组件基类
- **功能**:
- 注入 `BimEngine` 实例
- 提供 `emit()``on()` 辅助方法
- 定义抽象 `destroy()` 方法
- **使用**: 所有 Manager 类继承此类
### 3.2 主引擎文件
#### `bim-engine.ts`
- **作用**: SDK 主入口类
- **功能**:
- 初始化所有 Manager
- 管理主题和语言
- 提供事件总线功能
- 暴露公共 API
- **依赖**: EventEmitter、所有 Manager、Service
#### `index.ts`
- **作用**: SDK 入口文件
- **功能**: 导出所有公共 API
- **导出内容**:
- `BimEngine` 主类
- `BimButtonGroup``Toolbar` 组件
- 类型定义 (`EngineOptions``ModelLoadOptions` 等)
- `createEngine` 函数(从第三方 SDK 重新导出)
### 3.3 组件目录 (`src/components/`)
#### `dialog/`
- **`index.ts`**: `BimDialog` 类 - 通用弹窗组件
- 支持拖拽、缩放
- 支持自定义内容和样式
- 实现 `IBimComponent` 接口
- **`index.type.ts`**: 弹窗类型定义 (`DialogOptions``DialogPosition` 等)
- **`index.css`**: 弹窗样式
- **`bimInfoDialog/index.ts`**: `BimInfoDialog` 类 - 信息弹窗(继承 `BimDialog`
#### `button-group/`
- **`index.ts`**: `BimButtonGroup` 类 - 通用按钮组组件
- 支持按钮、菜单类型
- 支持分组、嵌套菜单
- 支持主题和国际化
- **`index.type.ts`**: 按钮组类型定义 (`ButtonConfig``ButtonGroupOptions` 等)
- **`index.css`**: 按钮组样式
- **`toolbar/index.ts`**: `Toolbar` 类 - 底部工具栏(继承 `BimButtonGroup`
- **`toolbar/buttons/`**: 工具栏按钮配置
- `home/`: 首页按钮
- `info/`: 信息按钮
- `location/`: 定位按钮
- `setting/`: 设置按钮
- `walk/`: 漫游相关按钮(菜单、人物、鸟瞰)
#### `engine/`
- **`index.ts`**: `Engine` 类 - 3D 引擎组件
- 封装第三方 3D 引擎 SDK
- 实现延迟初始化
- 管理引擎生命周期
- **`types.ts`**: 引擎类型定义 (`EngineOptions``ModelLoadOptions`)
2025-12-22 14:31:23 +08:00
#### `tab/`
- **`index.ts`**: `BimTab` 类 - 固定标签页组件(不支持运行时增删)
- 管理标签头与内容切换,可托管 `content` 或通过 `onChange` 外部切换
- 实现 `IBimComponent` 接口
- **`index.type.ts`**: 标签页类型定义
- **`index.css`**: 标签页样式
2025-12-22 18:48:38 +08:00
#### `measure-panel/`
- **`index.ts`**: `MeasurePanel` 类 - 测量面板组件(仅 UI不包含真实测量算法
- 顶部8 种测量方式按钮(默认显示前 4 种,可展开/收起)
- 中部:显示“当前测量方式”与“测量结果”(结果由外部注入)
- 底部:删除全部/设置入口(本期仅预留方法/回调)
- 实现 `IBimComponent` 接口,支持主题与国际化
- **`types.ts`**: 测量面板类型定义(`MeasureMode``MeasureResult``MeasurePanelOptions`
- **`index.css`**: 测量面板样式
2025-12-08 10:02:24 +08:00
### 3.4 管理器目录 (`src/managers/`)
#### `dialog-manager.ts`
- **作用**: 弹窗管理器
- **功能**:
- 创建和管理弹窗实例
- 监听 `ui:open-dialog` 事件
- 统一应用主题
- **继承**: `BimComponent`
#### `toolbar-manager.ts`
- **作用**: 底部工具栏管理器
- **功能**:
- 创建和管理工具栏实例
- 提供工具栏操作 API添加按钮、设置可见性等
- **继承**: `BimComponent`
#### `button-group-manager.ts`
- **作用**: 通用按钮组管理器
- **功能**:
- 创建和管理通用按钮组实例
- 支持多个按钮组并存
- **继承**: `BimComponent`
#### `engine-manager.ts`
- **作用**: 3D 引擎管理器
- **功能**:
- 管理 3D 引擎生命周期
- 提供引擎操作 API初始化、加载模型等
- 延迟初始化模式
- **继承**: `BimComponent`
### 3.5 服务目录 (`src/services/`)
#### `theme.ts`
- **作用**: 主题管理器(单例)
- **功能**:
- 管理当前主题配置
- 提供主题切换 API
- 支持主题变更订阅
- **导出**: `themeManager` 单例实例
#### `locale.ts`
- **作用**: 语言管理器(单例)
- **功能**:
- 管理当前语言配置
- 提供语言切换 API
- 提供翻译函数 `t(key)`
- 支持语言变更订阅
- **导出**: `localeManager` 单例实例、`t()` 翻译函数
### 3.6 主题目录 (`src/themes/`)
#### `types.ts`
- **作用**: 主题类型定义
- **内容**: `ThemeConfig` 接口、`ThemeType` 类型
#### `presets.ts`
- **作用**: 预设主题配置
- **内容**: `darkTheme``lightTheme` 预设配置对象
### 3.7 国际化目录 (`src/locales/`)
#### `types.ts`
- **作用**: 国际化类型定义
- **内容**:
- `LocaleType`: 支持的语言类型(`'zh-CN' | 'en-US'`
- `TranslationDictionary`: 翻译字典接口,定义所有翻译键的结构
#### `zh-CN.ts`
- **作用**: 中文翻译字典
- **内容**: 所有中文翻译文本,结构必须与 `TranslationDictionary` 接口一致
#### `en-US.ts`
- **作用**: 英文翻译字典
- **内容**: 所有英文翻译文本,结构必须与 `TranslationDictionary` 接口一致
### 3.8 类型定义目录 (`src/types/`)
#### `component.ts`
- **作用**: 组件接口定义
- **内容**: `IBimComponent` 接口
#### `events.ts`
- **作用**: 事件类型定义
- **内容**: `EngineEvents` 接口,定义所有事件类型和 payload 结构
### 3.9 样式文件
#### `bim-engine.css`
- **作用**: 全局样式
- **位置**: `src/bim-engine.css`
- **内容**: 基础样式、CSS 变量定义
### 3.10 组件详细文档目录 (`docs/components/`)
#### 文档说明
- **作用**: 存放每个组件的详细文档
- **用途**: 供 AI 根据文档重现组件,包含完整的实现细节
- **维护规则**: 组件有更改时,必须同步更新对应的组件文档
#### 文档列表
- `dialog.md` - Dialog 组件详细文档
- `button-group.md` - ButtonGroup 组件详细文档
- `engine.md` - Engine 组件详细文档
2025-12-22 14:31:23 +08:00
- `tab.md` - Tab 组件详细文档
2025-12-08 10:02:24 +08:00
#### 文档内容结构
每个组件文档包含以下部分:
1. 组件概述(基本信息、在 SDK 中的位置)
2. 组件类 API 文档(所有公共方法、参数、返回值)
3. 分化组件说明(如 Toolbar 继承自 ButtonGroup
4. Manager API 文档Manager 的所有公共方法)
5. UI 详细描述DOM 结构、CSS 类名、交互行为)
6. 逻辑流程详细描述(初始化、生命周期、事件处理)
7. 国际化支持(使用的翻译键、语言变更处理)
8. 主题支持(使用的主题变量、主题变更处理)
9. 使用示例(基本使用、高级使用)
10. 实现细节(关键算法、性能优化、注意事项)
11. 类型定义
12. 文件清单
**重要**: 组件文档必须非常详细,详细到其他 AI 可以直接根据文档重现组件。
---
## 4. 组件和事件清单
### 4.0 组件与 Manager 的关系(重要)
#### 核心原则
**组件是独立的实现,但使用组件必须通过 Manager不允许直接使用组件类。**
#### 设计理念
- **组件 (`components/`)**: 独立的 UI 组件实现,负责具体的功能逻辑
- **Manager (`managers/`)**: 组件管理器,负责创建、管理和协调组件实例
- **BimEngine**: 总控制器,通过 Manager 统一管理所有组件
#### 为什么必须通过 Manager
2025-12-22 15:39:58 +08:00
1. **强制统一管理**: SDK 入口不再导出组件类(如 `BimDialog`),物理上切断了直接实例化的可能。
2025-12-08 10:02:24 +08:00
2. **主题和语言**: Manager 统一应用主题和国际化,保证一致性
3. **事件总线**: Manager 可以监听和发送事件,实现组件间解耦通信
4. **容器管理**: Manager 管理组件的挂载容器,避免冲突
5. **API 封装**: Manager 提供统一的公共 API隐藏组件实现细节
#### 使用示例
2025-12-22 15:39:58 +08:00
**❌ 错误方式 - 尝试直接导入组件:**
2025-12-08 10:02:24 +08:00
```typescript
2025-12-22 15:39:58 +08:00
// 错误BimDialog 类未导出,会导致编译错误
import { BimDialog } from 'bim-engine-sdk';
// Error: Module 'bim-engine-sdk' has no exported member 'BimDialog'.
2025-12-08 10:02:24 +08:00
```
**✅ 正确方式 - 通过 Manager 使用:**
```typescript
// 正确:通过 BimEngine 的 Manager 使用组件
import { BimEngine } from 'bim-engine-sdk';
const engine = new BimEngine('container', {
locale: 'zh-CN',
theme: 'dark'
});
// 通过 DialogManager 创建弹窗
const dialog = engine.dialog.create({
title: '测试弹窗',
content: '这是内容'
});
```
#### 组件导出说明
2025-12-22 15:39:58 +08:00
`src/index.ts` **仅导出** `BimEngine` 主类和必要的类型定义(如 `DialogOptions`)。
所有具体的组件类(如 `BimDialog``Toolbar`)均视为**内部实现细节**,不对外暴露。这意味着:
- 用户不能继承这些组件类进行扩展。
- 用户必须依赖 SDK 提供的 Manager API。
- 这保证了 SDK 内部架构的封闭性和稳定性。
2025-12-08 10:02:24 +08:00
### 4.1 Manager 类清单
| 类名 | 文件路径 | 功能 | 继承关系 |
|------|---------|------|---------|
| `DialogManager` | `src/managers/dialog-manager.ts` | 管理弹窗实例 | `BimComponent` |
| `ToolbarManager` | `src/managers/toolbar-manager.ts` | 管理底部工具栏 | `BimComponent` |
| `ButtonGroupManager` | `src/managers/button-group-manager.ts` | 管理通用按钮组 | `BimComponent` |
| `EngineManager` | `src/managers/engine-manager.ts` | 管理 3D 引擎 | `BimComponent` |
| `RightKeyManager` | `src/managers/right-key-manager.ts` | 管理右键菜单 (Context Menu) | `BimComponent` |
2025-12-22 15:39:58 +08:00
| `ModelTreeManager` | `src/managers/model-tree-manager.ts` | 模型树业务管理器 | `BimComponent` |
| `PropertyPanelManager` | `src/managers/property-panel-manager.ts` | 属性面板业务管理器 (演示 Collapse) | `BimComponent` |
2025-12-22 18:48:38 +08:00
| `MeasureDialogManager` | `src/managers/measure-dialog-manager.ts` | 测量弹窗管理器 | `BimComponent` |
2025-12-08 10:02:24 +08:00
### 4.2 组件类清单
| 类名 | 文件路径 | 功能 | 实现接口 |
|------|---------|------|---------|
| `BimDialog` | `src/components/dialog/index.ts` | 通用弹窗组件 | `IBimComponent` |
| `BimInfoDialog` | `src/components/dialog/bimInfoDialog/index.ts` | 信息弹窗组件 | 继承 `BimDialog` |
| `BimButtonGroup` | `src/components/button-group/index.ts` | 通用按钮组组件 | `IBimComponent` |
| `Toolbar` | `src/components/button-group/toolbar/index.ts` | 底部工具栏组件 | 继承 `BimButtonGroup` |
| `Engine` | `src/components/engine/index.ts` | 3D 引擎组件 | `IBimComponent` |
| `BimRightKey` | `src/components/right-key/index.ts` | 右键浮层容器 | `IBimComponent` |
| `BimMenu` | `src/components/menu/index.ts` | 通用菜单列表 | `IBimComponent` |
| `BimTree` | `src/components/tree/index.ts` | 通用树形组件 | `IBimComponent` |
2025-12-22 15:39:58 +08:00
| `BimTab` | `src/components/tab/index.ts` | 固定标签页组件 | `IBimComponent` |
| `BimCollapse` | `src/components/collapse/index.ts` | 折叠面板组件 | `IBimComponent` |
| `BimDescription` | `src/components/description/index.ts` | 描述列表组件 (Key-Value) | `IBimComponent` |
2025-12-22 18:48:38 +08:00
| `MeasurePanel` | `src/components/measure-panel/index.ts` | 测量面板组件(仅 UI | `IBimComponent` |
2025-12-08 10:02:24 +08:00
### 4.3 服务类清单
| 类名 | 文件路径 | 功能 | 模式 |
|------|---------|------|------|
| `ThemeManager` | `src/services/theme.ts` | 主题管理 | 单例 |
| `LocaleManager` | `src/services/locale.ts` | 语言管理 | 单例 |
### 4.4 事件总线定义
#### 事件类型 (`EngineEvents`)
定义在 `src/types/events.ts`:
```typescript
interface EngineEvents {
// UI 事件
'ui:open-dialog': { id: string; data?: any };
'ui:close-dialog': { id: string };
// 引擎事件
'engine:model-loaded': { url: string };
'engine:object-clicked': { objectId: string; position: { x: number, y: number, z: number } };
// 树组件事件
'ui:tree-node-check': { id: string; checked: boolean; node: any };
'ui:tree-node-select': { id: string; selected: boolean; node: any };
'ui:tree-node-expand': { id: string; expanded: boolean };
2025-12-08 10:02:24 +08:00
// 系统事件
'sys:theme-changed': { theme: string };
'sys:locale-changed': { locale: string };
}
```
#### 事件命名规范
- **UI 事件**: `ui:` 前缀,如 `ui:open-dialog`
- **引擎事件**: `engine:` 前缀,如 `engine:model-loaded`
- **系统事件**: `sys:` 前缀,如 `sys:theme-changed`
#### 事件使用方式
**发送事件**:
```typescript
// 在 BimComponent 子类中
this.emit('ui:open-dialog', { id: 'info' });
```
**监听事件**:
```typescript
// 在 BimComponent 子类中
// 返回取消订阅函数
const unsubscribe = this.on('ui:open-dialog', (payload) => {
console.log('收到事件:', payload);
});
// 组件销毁时取消订阅
unsubscribe();
```
#### 使用场景判断
**✅ 使用直接调用方法的场景**
- 简单的 API 调用,如 `engine.dialog.create()`
- 需要立即得到结果的操作
- 单一调用者,不需要多个监听者
- 性能敏感的操作
**✅ 使用事件总线的场景**
- 需要多个组件同时响应的事件(如模型加载完成)
- 跨多层组件传递信息
- 解耦需求,降低组件间直接依赖
- 异步通知场景
- 需要动态添加/移除监听者的场景
**示例对比**
```typescript
// 场景 1: 简单操作 - 使用直接调用
// 用户代码直接调用,简单直接
engine.dialog.create({
title: t('dialog.title'),
content: 'Hello'
});
// 场景 2: 复杂场景 - 使用事件总线
// 按钮点击后,需要通知多个组件(弹窗、日志、统计等)
this.emit('ui:open-dialog', { id: 'info', data: { source: 'toolbar' } });
// 多个组件可以同时监听
// DialogManager 监听并打开弹窗
this.on('ui:open-dialog', (payload) => {
if (payload.id === 'info') {
this.showInfoDialog();
}
});
// AnalyticsManager 监听并记录统计
this.on('ui:open-dialog', (payload) => {
this.trackEvent('dialog_opened', payload);
});
```
### 4.5 核心基类
| 类名 | 文件路径 | 功能 | 继承/实现 |
|------|---------|------|----------|
| `EventEmitter` | `src/core/event-emitter.ts` | 事件总线基础类 | - |
| `BimComponent` | `src/core/component.ts` | 组件基类 | 抽象类 |
| `BimEngine` | `src/bim-engine.ts` | 主引擎类 | 继承 `EventEmitter` |
---
## 4.6 国际化实现指南
### 4.6.1 国际化的重要性
**所有用户可见的文本都必须支持国际化,这是强制要求。**
- 项目支持多语言(目前:中文、英文)
- 所有 UI 文本必须通过翻译函数获取
- 严禁在代码中硬编码任何语言的文本
### 4.6.2 国际化实现方式
#### 步骤 1: 在翻译字典中添加键值
**在 `src/locales/types.ts` 中定义类型:**
```typescript
export interface TranslationDictionary {
// ... 现有键
myComponent: {
title: string;
description: string;
buttonText: string;
};
}
```
**在 `src/locales/zh-CN.ts` 中添加中文翻译:**
```typescript
export const zhCN: TranslationDictionary = {
// ... 现有内容
myComponent: {
title: '我的组件',
description: '这是组件描述',
buttonText: '点击按钮',
},
};
```
**在 `src/locales/en-US.ts` 中添加英文翻译:**
```typescript
export const enUS: TranslationDictionary = {
// ... 现有内容
myComponent: {
title: 'My Component',
description: 'This is component description',
buttonText: 'Click Button',
},
};
```
#### 步骤 2: 在组件中使用翻译函数
**导入翻译函数:**
```typescript
import { t, localeManager } from '../../services/locale';
```
**使用翻译函数:**
```typescript
// 在组件中使用
const title = t('myComponent.title'); // 获取翻译文本
// 在 DOM 中使用
const titleEl = document.createElement('div');
titleEl.textContent = t('myComponent.title');
// 在 HTML 字符串中使用
const html = `<div>${t('myComponent.description')}</div>`;
```
#### 步骤 3: 监听语言变更
**在组件中订阅语言变更:**
```typescript
export class MyComponent implements IBimComponent {
private unsubscribeLocale: (() => void) | null = null;
public init() {
// 初始化时订阅语言变更
this.unsubscribeLocale = localeManager.subscribe(() => {
this.setLocales(); // 更新所有文本
});
// 初始设置
this.setLocales();
}
public setLocales(): void {
// 更新所有用户可见的文本
const titleEl = this.element.querySelector('.title');
if (titleEl) {
titleEl.textContent = t('myComponent.title');
}
}
public destroy() {
// 清理订阅
if (this.unsubscribeLocale) {
this.unsubscribeLocale();
this.unsubscribeLocale = null;
}
}
}
```
### 4.6.3 国际化注意事项
#### ✅ 必须做的
1. **所有用户可见文本使用 `t(key)`**
```typescript
// ✅ 正确
button.textContent = t('toolbar.home');
// ❌ 错误
button.textContent = '首页';
```
2. **翻译键使用有意义的路径**
```typescript
// ✅ 正确:按功能模块组织
t('toolbar.home')
t('dialog.title')
t('button.save')
// ❌ 错误:键名不清晰
t('text1')
t('label')
```
3. **在所有语言文件中添加翻译**
- 添加新键时,必须同时更新 `zh-CN.ts``en-US.ts`
- 确保所有语言文件的结构一致
4. **实现 `setLocales()` 方法**
- 所有组件必须实现 `setLocales()` 方法
- 在方法中更新所有用户可见的文本
5. **订阅语言变更**
- 组件初始化时订阅 `localeManager.subscribe()`
- 组件销毁时取消订阅
#### ❌ 禁止做的
1. **禁止硬编码文本**
```typescript
// ❌ 错误:硬编码中文
const title = '首页';
// ❌ 错误:硬编码英文
const title = 'Home';
// ✅ 正确:使用翻译函数
const title = t('toolbar.home');
```
2. **禁止在翻译键中使用变量**
```typescript
// ❌ 错误:动态拼接键名
t(`toolbar.${buttonId}`);
// ✅ 正确:使用完整的键名
t('toolbar.home');
```
3. **禁止在翻译文本中拼接变量**
```typescript
// ❌ 错误:在翻译文本中拼接
const text = t('dialog.message') + userName;
// ✅ 正确:使用占位符(需要在翻译字典中支持)
// 注意:当前实现不支持占位符,需要扩展 LocaleManager
```
4. **禁止忽略语言变更**
- 组件必须响应语言切换
- 不能只在初始化时设置文本
### 4.6.4 国际化最佳实践
#### 翻译键的组织结构
```typescript
// 按功能模块组织
TranslationDictionary {
toolbar: { // 工具栏相关
home: string;
info: string;
},
dialog: { // 弹窗相关
title: string;
content: string;
},
button: { // 按钮相关
save: string;
cancel: string;
},
message: { // 消息相关
success: string;
error: string;
}
}
```
#### 组件中的国际化实现示例
```typescript
import { t, localeManager } from '../../services/locale';
import { IBimComponent } from '../../types/component';
export class MyDialog implements IBimComponent {
private element: HTMLElement;
private unsubscribeLocale: (() => void) | null = null;
constructor(container: HTMLElement) {
this.element = this.createDOM();
container.appendChild(this.element);
}
public init() {
// 订阅语言变更
this.unsubscribeLocale = localeManager.subscribe(() => {
this.setLocales();
});
// 初始设置
this.setLocales();
}
public setLocales(): void {
// 更新标题
const titleEl = this.element.querySelector('.dialog-title');
if (titleEl) {
titleEl.textContent = t('dialog.myDialog.title');
}
// 更新内容
const contentEl = this.element.querySelector('.dialog-content');
if (contentEl) {
contentEl.textContent = t('dialog.myDialog.content');
}
// 更新按钮
const buttonEl = this.element.querySelector('.dialog-button');
if (buttonEl) {
buttonEl.textContent = t('button.confirm');
}
}
public destroy() {
if (this.unsubscribeLocale) {
this.unsubscribeLocale();
this.unsubscribeLocale = null;
}
this.element.remove();
}
}
```
#### 添加新语言支持
1.`src/locales/types.ts` 中扩展 `LocaleType`
```typescript
export type LocaleType = 'zh-CN' | 'en-US' | 'ja-JP'; // 添加日语
```
2. 创建新的翻译文件 `src/locales/ja-JP.ts`
```typescript
import { TranslationDictionary } from './types';
export const jaJP: TranslationDictionary = {
// 添加所有翻译
};
```
3.`src/services/locale.ts` 中注册新语言:
```typescript
import { jaJP } from '../locales/ja-JP';
private messages: Record<LocaleType, TranslationDictionary> = {
'zh-CN': zhCN,
'en-US': enUS,
'ja-JP': jaJP, // 添加新语言
};
```
### 4.6.5 国际化检查清单
在开发新功能时,确保:
- [ ] 所有用户可见的文本都使用 `t(key)` 函数
- [ ]`types.ts` 中定义了新的翻译键类型
- [ ]`zh-CN.ts` 中添加了中文翻译
- [ ]`en-US.ts` 中添加了英文翻译
- [ ] 组件实现了 `setLocales()` 方法
- [ ] 组件订阅了语言变更事件
- [ ] 组件销毁时取消了语言订阅
- [ ] 没有硬编码任何语言的文本
- [ ] 翻译键名清晰、有意义
---
## 5. AI 工作规则
### 5.1 AI 编码规范
#### 语言要求(强制)
- **所有输出必须使用中文**,包括:
- 代码注释 (**强制:所有代码注释必须使用中文,解释清晰详细**)
2025-12-08 10:02:24 +08:00
- 文档说明
- 与用户交流
- 错误信息
- 日志输出
- **思考过程也必须使用中文**
- 分析问题时用中文思考
- 解释代码逻辑时用中文
- 讨论设计方案时用中文
- **代码中的字符串**:根据业务需求,但注释和文档必须中文
#### 代码可读性
- **优先保证代码可读性**,有时可以不使用高级函数,使用低级函数
- **必须添加详细的中文注释**,解释代码逻辑和设计意图
- 函数、类、接口必须有 JSDoc 注释(使用中文)
- 复杂逻辑必须添加行内注释说明
#### 代码风格
- 使用 TypeScript 严格模式
- 遵循项目现有的命名规范(见 2.3 节)
- 保持代码格式一致(使用项目配置的格式化工具)
- 保持缩进和空行的一致性
#### 类型安全
- 充分利用 TypeScript 类型系统
- 避免使用 `any`,必要时使用 `unknown`
- 为所有公共 API 提供类型定义
- 使用类型推断,但复杂类型必须显式声明
#### 组件使用规范
- **严禁直接使用组件类**,必须通过 Manager 使用(见 4.0 节)
- 新增组件时,必须创建对应的 Manager
- Manager 必须继承 `BimComponent` 基类
- 组件必须实现 `IBimComponent` 接口
- **组件必须支持国际化**(见 4.6 节)
#### 注释规范
```typescript
/**
* 函数功能描述(中文)
* @param param1 参数说明(中文)
* @param param2 参数说明(中文)
* @returns 返回值说明(中文)
*/
function example(param1: string, param2: number): boolean {
// 行内注释说明关键逻辑(中文)
return true;
}
```
#### 错误处理规范
- 所有异步操作必须有错误处理
- 使用 `try-catch` 捕获可能的异常
- 错误信息必须使用中文
- 提供有意义的错误信息,帮助调试
#### 性能考虑
- 使用 `requestAnimationFrame` 优化动画性能
- 避免频繁的 DOM 操作,使用批量更新
- 合理使用事件委托,减少事件监听器数量
- 及时清理不需要的监听器和定时器
### 5.2 问答方式和开发流程规范
#### 用户询问"如何实现"时的处理流程
**当用户询问如何实现某个功能时,必须遵循以下流程:**
1. **分析需求**:用中文理解用户需求,明确要实现的功能
2. **制定详细开发计划**:必须包含以下内容:
- **需要修改的文件列表**
- 列出每个需要修改的文件路径
- 说明每个文件的修改内容(添加什么、修改什么)
- **需要新增的文件列表**
- 列出每个需要新增的文件路径
- 说明每个文件的作用和内容概要
- **需要删除的文件列表**
- 列出每个需要删除的文件路径
- 说明删除的原因
- **注意**:删除的文件必须移动到回收文件夹,不能直接删除
- **每个文件的作用说明**
- 详细说明每个文件在整体功能中的作用
- 说明文件之间的依赖关系
- **对整体结构的影响**
- 说明对现有架构的影响
- 说明对现有功能的影响
- 说明是否需要更新文档
- 说明可能的风险点
3. **展示开发计划**:以清晰的格式展示给用户
4. **等待用户确认****在用户明确同意之前,绝对不能修改任何代码**
5. **用户同意后执行**:只有在用户明确表示同意后,才能开始修改代码
**示例格式**
```
## 开发计划
### 需要修改的文件
1. `src/managers/dialog-manager.ts`
- 修改:添加新的 `showCustomDialog()` 方法
- 作用:提供自定义弹窗的快捷方法
2. `src/types/events.ts`
- 修改:在 `EngineEvents` 接口中添加 `'ui:custom-dialog'` 事件类型
- 作用:定义新的事件类型,支持事件总线通信
### 需要新增的文件
1. `src/components/dialog/customDialog/index.ts`
- 作用:实现自定义弹窗组件
- 内容:包含 CustomDialog 类,实现 IBimComponent 接口
2. `src/components/dialog/customDialog/index.css`
- 作用:自定义弹窗的样式文件
### 需要删除的文件
1. `src/components/dialog/oldDialog.ts`
- 原因:已被新组件替代
- **处理方式**:移动到 `.recycle/YYYY-MM-DD/` 文件夹(使用当前日期)
### 对整体结构的影响
- **架构影响**:新增一个 Dialog 子类型,不影响现有架构
- **功能影响**:不影响现有弹窗功能,只是新增功能
- **文档更新**:需要更新 AI_COLLABORATION.md 中的组件清单
- **风险点**:无重大风险,向后兼容
请确认是否按照此计划进行开发?
```
#### 用户直接要求修改时的处理
**当用户直接要求修改代码时(如"帮我修改XXX"、"实现XXX功能"),可以:**
- 直接执行代码修改
- 但仍需遵循其他规范(国际化、组件使用规范等)
- 删除文件时仍需移动到回收文件夹
#### 文件删除规范(强制)
**严禁直接删除文件,必须遵循以下流程:**
1. **创建回收文件夹**(如果不存在):
- 在项目根目录创建 `.recycle/` 文件夹
- 此文件夹用于存放被删除的文件
2. **按时间组织文件夹**
-`.recycle/` 下按日期创建子文件夹,格式:`YYYY-MM-DD`
- 例如:`2024-01-15``2024-12-25`
- 同一天删除的文件存放在同一个日期文件夹中
3. **移动文件而非删除**
```bash
# 错误方式 ❌
rm src/old-file.ts
# 正确方式 ✅
# 获取当前日期格式YYYY-MM-DD
DATE=$(date +%Y-%m-%d)
mkdir -p .recycle/$DATE
mv src/old-file.ts .recycle/$DATE/src/old-file.ts
```
4. **保持目录结构**
- 在日期文件夹中保持原文件的目录结构
- 例如:`src/components/old.ts``.recycle/2024-01-15/src/components/old.ts`
5. **添加删除说明**(可选):
- 在对应日期文件夹中创建 `README.md` 记录删除原因
- 格式:
```
## 2024-01-15 删除的文件
- `src/components/old.ts`: 被新组件替代
- `src/managers/old-manager.ts`: 功能重构,使用新 Manager
```
6. **恢复文件**
- 如果发现误删,可以从对应日期文件夹中恢复
- 恢复后从 `.recycle/` 中移除
**回收文件夹结构示例**
```
.recycle/
├── 2024-01-15/
│ ├── README.md
│ └── src/
│ ├── components/
│ │ └── old-component.ts
│ └── managers/
│ └── old-manager.ts
├── 2024-02-20/
│ ├── README.md
│ └── src/
│ └── types/
│ └── old-types.ts
└── 2024-12-25/
├── README.md
└── demo/
└── old-demo.html
```
**注意事项**
- 日期格式必须使用 `YYYY-MM-DD`(如 `2024-01-15`
- 如果同一天删除多个文件,都存放在同一个日期文件夹中
- 日期文件夹按时间倒序排列,最新的在最前面
### 5.3 文档更新规则
#### 必须更新的情况
- **新增文件**: 在 "文件结构说明" 部分添加文件描述
- **删除文件**: 从文档中移除对应条目(但文件移动到 `.recycle/` 文件夹)
- **修改文件功能**: 更新对应文件的描述
- **新增组件**:
- 在 "组件和事件清单" 部分添加
- **必须创建对应的组件详细文档**(在 `docs/components/` 目录下)
- **修改组件**:
- 更新 "组件和事件清单" 部分
- **必须同步更新对应的组件详细文档**`docs/components/` 目录下的对应文档)
- **新增事件**: 在 "事件总线定义" 部分添加
- **修改架构**: 更新 "架构设计思想" 部分
- **修改构建流程**: 更新 "构建和运行" 部分
#### 更新方式
1. 修改代码后,立即更新本文档
2. 确保文档与代码保持一致
3. 如果发现文档过时,优先更新文档
### 5.4 思考和工作流程规范
#### 思考过程要求
- **所有思考过程必须使用中文**
- 分析问题时,用中文描述问题、分析思路、得出结论
- 解释代码时,用中文说明逻辑、设计意图、实现方式
- 讨论方案时,用中文描述优缺点、选择理由
#### 工作流程
1. **理解需求**:用中文理解用户需求,明确任务目标
2. **分析问题**:用中文分析问题,梳理相关代码和架构
3. **设计方案**:用中文设计解决方案,考虑边界情况
4. **实现代码**:编写代码,添加中文注释
5. **测试验证**:用中文描述测试结果和发现的问题
6. **更新文档**:用中文更新相关文档
#### 代码审查要点
- **检查开发流程规范**
- 如果是询问"如何实现",是否先提供了详细的开发计划
- 是否在用户同意后才修改代码
- 删除的文件是否移动到 `.recycle/` 文件夹而非直接删除
- 检查是否遵循组件使用规范(通过 Manager
- **检查是否支持国际化**
- 所有用户可见文本是否使用 `t(key)` 函数
- 是否在所有语言文件中添加了翻译
- 组件是否实现了 `setLocales()` 方法
- 组件是否订阅了语言变更事件
- 检查注释是否完整且为中文
- 检查错误处理是否完善
- 检查资源是否正确释放
- 检查类型定义是否完整
### 5.5 其他注意事项
#### 组件开发
- 所有 UI 组件必须实现 `IBimComponent` 接口
- 所有 Manager 必须继承 `BimComponent` 基类
- **组件必须通过 Manager 使用,不允许直接使用组件类**
- **组件必须支持国际化**(见 4.6 节):
- 所有用户可见文本使用 `t(key)` 函数
- 实现 `setLocales()` 方法
- 订阅语言变更事件
- 严禁硬编码任何语言的文本
- 组件销毁时必须清理所有资源(事件监听、定时器等)
- 新增组件时,必须同时创建对应的 Manager
#### 主题和国际化
- 组件必须支持主题切换(通过 `setTheme()` 方法)
- **组件必须支持国际化**(通过 `setLocales()` 方法)
- **所有用户可见的文本必须使用 `t(key)` 函数进行翻译**
- **严禁硬编码中文或英文文本**
- 新增文本时,必须在所有语言文件中添加对应的翻译键
- **详细实现方式请参考 4.6 节《国际化实现指南》**
#### 事件总线使用规范
- **根据场景选择通信方式**
- **简单场景**:使用直接调用方法(如 `engine.dialog.create()`
- **复杂场景**:使用事件总线(需要多个监听者、跨多层传递、解耦需求)
- **事件命名遵循规范**`ui:``engine:``sys:` 前缀)
- **事件监听必须清理**:组件销毁时取消所有事件订阅
- **类型安全**:使用 `EngineEvents` 接口确保事件类型正确
#### 性能优化
- 使用 `requestAnimationFrame` 优化动画性能
- 避免频繁的 DOM 操作,使用批量更新
- 合理使用事件委托,减少事件监听器数量
#### 错误处理
- 所有异步操作必须有错误处理
- 使用 `try-catch` 捕获可能的异常
- 提供有意义的错误信息
#### 测试
- 确保代码修改后不影响现有功能
- 在 demo 中测试新功能
- 检查控制台是否有错误或警告
### 5.6 常见任务指南
#### 添加新组件
1.`src/components/` 创建组件目录
2. 实现 `IBimComponent` 接口
3. 创建对应的类型定义文件
4. 创建对应的样式文件
5. **必须创建对应的 Manager**(在 `src/managers/` 目录)
6. **实现国际化支持**
-`src/locales/types.ts` 中添加翻译键类型
-`src/locales/zh-CN.ts``en-US.ts` 中添加翻译
- 在组件中实现 `setLocales()` 方法
- 订阅语言变更事件
7.`BimEngine` 中初始化 Manager 并暴露
8.`src/index.ts` 导出(如需要,但不推荐直接导出组件)
9. **创建组件详细文档**
-`docs/components/` 目录下创建对应的组件文档(如 `dialog.md`
- 文档必须包含以下 12 个部分(参考现有组件文档):
1. 组件概述
2. 组件类 API 文档
3. 分化组件说明
4. Manager API 文档
5. UI 详细描述
6. 逻辑流程详细描述
7. 国际化支持
8. 主题支持
9. 使用示例
10. 实现细节(供 AI 重现)
11. 类型定义
12. 文件清单
- **文档必须非常详细**,详细到其他 AI 可以直接根据文档重现组件
10. 更新本文档
**重要**:
- 组件必须通过 Manager 使用,不要直接导出组件类供外部使用
- 组件必须支持国际化,所有用户可见文本使用 `t(key)` 函数
- **组件有更改时,必须同步更新对应的组件详细文档**`docs/components/` 目录下的对应文档)
#### 添加新 Manager
1.`src/managers/` 创建 Manager 文件
2. 继承 `BimComponent` 基类
3.`BimEngine` 中初始化
4.`BimEngine` 中暴露公共属性
5. 更新本文档
#### 添加新事件
1. **判断是否需要事件总线**
- 如果只需要简单的一对一调用 → 使用直接方法调用
- 如果需要多个监听者或跨多层传递 → 使用事件总线
2. 如果使用事件总线,在 `src/types/events.ts``EngineEvents` 接口中添加事件类型
3. 在相关组件中发送/监听事件
4. 确保组件销毁时取消事件订阅
5. 更新本文档
#### 修改主题配置
1.`src/themes/presets.ts` 修改预设主题
2. 或在 `src/themes/types.ts` 扩展 `ThemeConfig` 接口
3. 确保所有组件正确应用新主题属性
4. 更新本文档(如主题结构有变化)
#### 添加新的翻译文本
1.`src/locales/types.ts``TranslationDictionary` 接口中添加新的键
2.`src/locales/zh-CN.ts` 中添加中文翻译
3.`src/locales/en-US.ts` 中添加英文翻译
4. 在相关组件中使用 `t(key)` 函数获取翻译
5. 确保组件实现了 `setLocales()` 方法并订阅语言变更
6. 更新本文档(如添加新语言支持)
---
## 📝 文档维护记录
| 日期 | 修改内容 | 修改人 |
|------|---------|--------|
| 2024-XX-XX | 初始创建 | AI Assistant |
---
**重要提醒**: 本文档是 AI 协作的重要参考,请保持文档与代码同步更新!