369 lines
7.5 KiB
Markdown
369 lines
7.5 KiB
Markdown
# 事件系统设计
|
||
|
||
**设计日期**:2025-01-28
|
||
**设计范围**:数据库客户端全局事件系统
|
||
**状态**:设计阶段
|
||
|
||
---
|
||
|
||
## 一、设计概述
|
||
|
||
### 1.1 设计目标
|
||
|
||
- **简洁统一**:所有组件使用统一的事件命名和参数格式
|
||
- **易于扩展**:新增事件时,遵循统一规范,易于维护
|
||
- **类型安全**:使用 TypeScript 类型定义,确保类型安全
|
||
- **功能强大**:支持事件传递、事件拦截、事件日志等高级功能
|
||
|
||
### 1.2 设计原则
|
||
|
||
1. **命名规范**:事件名称使用 kebab-case,语义清晰
|
||
2. **参数统一**:事件参数使用对象格式,包含必要上下文信息
|
||
3. **类型定义**:所有事件都有明确的 TypeScript 类型定义
|
||
4. **文档完善**:每个事件都有清晰的文档说明
|
||
|
||
---
|
||
|
||
## 二、事件分类
|
||
|
||
### 2.1 连接相关事件
|
||
|
||
```typescript
|
||
// 连接选择
|
||
'connection-select': {
|
||
connection: DbConnection
|
||
database?: string // 可选,选中的数据库
|
||
}
|
||
|
||
// 连接编辑
|
||
'connection-edit': {
|
||
connectionId: number
|
||
}
|
||
|
||
// 连接删除
|
||
'connection-delete': {
|
||
connectionId: number
|
||
}
|
||
|
||
// 连接刷新
|
||
'connection-refresh': {
|
||
connectionId?: number // 可选,不提供则刷新所有
|
||
}
|
||
```
|
||
|
||
### 2.2 表结构相关事件
|
||
|
||
```typescript
|
||
// 查看表结构
|
||
'table-structure': {
|
||
connectionId: number
|
||
database: string
|
||
tableName: string // 表名/集合名/Key名
|
||
dbType: 'mysql' | 'mongo' | 'redis'
|
||
nodeType: 'table' | 'collection' | 'key' | 'database' | 'connection'
|
||
}
|
||
|
||
// 表选择(生成SQL)
|
||
'table-select': {
|
||
connectionId: number
|
||
database: string
|
||
tableName: string
|
||
sql?: string // 可选,预生成的SQL
|
||
}
|
||
```
|
||
|
||
### 2.3 SQL执行相关事件
|
||
|
||
```typescript
|
||
// SQL执行
|
||
'sql-execute': {
|
||
sql: string
|
||
connectionId: number
|
||
database?: string
|
||
}
|
||
|
||
// SQL执行完成
|
||
'sql-execute-complete': {
|
||
result: SqlResult
|
||
error?: string
|
||
}
|
||
```
|
||
|
||
### 2.4 编辑器相关事件
|
||
|
||
```typescript
|
||
// SQL插入
|
||
'sql-insert': {
|
||
sql: string
|
||
tabKey?: string // 可选,指定Tab
|
||
}
|
||
|
||
// Tab切换
|
||
'tab-switch': {
|
||
tabKey: string
|
||
}
|
||
|
||
// Tab关闭
|
||
'tab-close': {
|
||
tabKey: string
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 三、事件系统架构
|
||
|
||
### 3.1 事件总线设计
|
||
|
||
```typescript
|
||
// 事件总线接口
|
||
interface EventBus {
|
||
// 注册事件监听器
|
||
on<T = any>(event: string, handler: (data: T) => void): () => void
|
||
|
||
// 注册一次性事件监听器
|
||
once<T = any>(event: string, handler: (data: T) => void): void
|
||
|
||
// 移除事件监听器
|
||
off(event: string, handler?: Function): void
|
||
|
||
// 触发事件
|
||
emit<T = any>(event: string, data: T): void
|
||
|
||
// 清除所有监听器
|
||
clear(): void
|
||
}
|
||
|
||
// 全局事件总线实例
|
||
export const eventBus = createEventBus()
|
||
```
|
||
|
||
### 3.2 组件事件映射
|
||
|
||
```typescript
|
||
// ConnectionTree 组件事件
|
||
interface ConnectionTreeEvents {
|
||
'connection-select': { connection: DbConnection; database?: string }
|
||
'connection-edit': { connectionId: number }
|
||
'connection-delete': { connectionId: number }
|
||
'table-select': { connectionId: number; database: string; tableName: string }
|
||
'table-structure': {
|
||
connectionId: number
|
||
database: string
|
||
tableName: string
|
||
dbType: 'mysql' | 'mongo' | 'redis'
|
||
nodeType: string
|
||
}
|
||
'new-connection': void
|
||
'show-bookmarks': void
|
||
'show-templates': void
|
||
}
|
||
|
||
// SqlEditor 组件事件
|
||
interface SqlEditorEvents {
|
||
'execute': { sql: string }
|
||
'execute-selected': { sql: string }
|
||
'sql-insert': { sql: string; tabKey?: string }
|
||
'tab-switch': { tabKey: string }
|
||
'tab-close': { tabKey: string }
|
||
'toggle-editor': void
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 四、事件命名规范
|
||
|
||
### 4.1 命名规则
|
||
|
||
- **格式**:`<组件>-<动作>` 或 `<功能>-<动作>`
|
||
- **示例**:
|
||
- `connection-select`:连接选择
|
||
- `table-structure`:表结构查看
|
||
- `sql-execute`:SQL执行
|
||
|
||
### 4.2 动作词汇表
|
||
|
||
| 动作 | 说明 | 示例 |
|
||
|------|------|------|
|
||
| select | 选择 | `connection-select` |
|
||
| edit | 编辑 | `connection-edit` |
|
||
| delete | 删除 | `connection-delete` |
|
||
| create | 创建 | `tab-create` |
|
||
| close | 关闭 | `tab-close` |
|
||
| switch | 切换 | `tab-switch` |
|
||
| execute | 执行 | `sql-execute` |
|
||
| insert | 插入 | `sql-insert` |
|
||
| refresh | 刷新 | `connection-refresh` |
|
||
|
||
---
|
||
|
||
## 五、事件参数设计
|
||
|
||
### 5.1 参数原则
|
||
|
||
1. **对象格式**:所有事件参数使用对象,不使用多个参数
|
||
2. **必要信息**:包含事件处理所需的所有上下文信息
|
||
3. **可选字段**:使用可选字段(`?`)标记非必需信息
|
||
4. **类型明确**:所有字段都有明确的类型定义
|
||
|
||
### 5.2 参数示例
|
||
|
||
```typescript
|
||
// ✅ 好的设计:对象格式,类型明确
|
||
emit('table-structure', {
|
||
connectionId: 1,
|
||
database: 'test',
|
||
tableName: 'users',
|
||
dbType: 'mysql',
|
||
nodeType: 'table'
|
||
})
|
||
|
||
// ❌ 不好的设计:多个参数,类型不明确
|
||
emit('table-structure', 1, 'test', 'users', 'mysql', 'table')
|
||
```
|
||
|
||
---
|
||
|
||
## 六、事件处理流程
|
||
|
||
### 6.1 事件触发流程
|
||
|
||
```
|
||
组件内触发事件
|
||
↓
|
||
emit('event-name', data)
|
||
↓
|
||
父组件监听事件
|
||
↓
|
||
调用处理函数
|
||
↓
|
||
更新状态/执行操作
|
||
```
|
||
|
||
### 6.2 事件拦截机制(可选)
|
||
|
||
```typescript
|
||
// 事件拦截器接口
|
||
interface EventInterceptor {
|
||
beforeEmit?: (event: string, data: any) => boolean // 返回false阻止事件
|
||
afterEmit?: (event: string, data: any) => void // 事件触发后执行
|
||
}
|
||
|
||
// 注册拦截器
|
||
eventBus.addInterceptor(interceptor)
|
||
```
|
||
|
||
---
|
||
|
||
## 七、实现细节
|
||
|
||
### 7.1 事件类型定义
|
||
|
||
```typescript
|
||
// 事件类型定义文件:types/events.ts
|
||
export interface ConnectionSelectEvent {
|
||
connection: DbConnection
|
||
database?: string
|
||
}
|
||
|
||
export interface TableStructureEvent {
|
||
connectionId: number
|
||
database: string
|
||
tableName: string
|
||
dbType: 'mysql' | 'mongo' | 'redis'
|
||
nodeType: 'table' | 'collection' | 'key' | 'database' | 'connection'
|
||
}
|
||
|
||
// ... 其他事件类型
|
||
```
|
||
|
||
### 7.2 组件事件声明
|
||
|
||
```typescript
|
||
// ConnectionTree.vue
|
||
const emit = defineEmits<{
|
||
'connection-select': [data: ConnectionSelectEvent]
|
||
'table-structure': [data: TableStructureEvent]
|
||
'table-select': [data: TableSelectEvent]
|
||
// ... 其他事件
|
||
}>()
|
||
```
|
||
|
||
### 7.3 事件处理
|
||
|
||
```typescript
|
||
// index.vue
|
||
const handleTableStructure = (data: TableStructureEvent) => {
|
||
// 加载表结构
|
||
structureState.loadStructure(
|
||
data.connectionId,
|
||
data.database,
|
||
data.tableName,
|
||
data.dbType
|
||
)
|
||
// 切换到结构Tab
|
||
resultTab.value = 'structure'
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 八、扩展性设计
|
||
|
||
### 8.1 事件日志(开发模式)
|
||
|
||
```typescript
|
||
// 开发模式下记录所有事件
|
||
if (import.meta.env.DEV) {
|
||
eventBus.on('*', (event, data) => {
|
||
console.log(`[Event] ${event}`, data)
|
||
})
|
||
}
|
||
```
|
||
|
||
### 8.2 事件统计(可选)
|
||
|
||
```typescript
|
||
// 统计事件触发次数
|
||
const eventStats = new Map<string, number>()
|
||
|
||
eventBus.on('*', (event) => {
|
||
eventStats.set(event, (eventStats.get(event) || 0) + 1)
|
||
})
|
||
```
|
||
|
||
---
|
||
|
||
## 九、实现优先级
|
||
|
||
### P0(必须实现)
|
||
1. ✅ 事件类型定义(TypeScript)
|
||
2. ✅ 连接相关事件
|
||
3. ✅ 表结构相关事件
|
||
4. ✅ SQL执行相关事件
|
||
|
||
### P1(重要功能)
|
||
1. 事件参数验证
|
||
2. 事件文档完善
|
||
3. 事件处理错误处理
|
||
|
||
### P2(优化功能)
|
||
1. 事件拦截机制
|
||
2. 事件日志(开发模式)
|
||
3. 事件统计
|
||
|
||
---
|
||
|
||
## 十、总结
|
||
|
||
事件系统设计遵循以下原则:
|
||
|
||
1. **简洁统一**:统一的事件命名和参数格式
|
||
2. **类型安全**:完整的 TypeScript 类型定义
|
||
3. **易于扩展**:清晰的事件分类和命名规范
|
||
4. **功能强大**:支持事件拦截、日志等高级功能
|
||
|
||
通过以上设计,可以实现一个简洁、强大、易扩展的事件系统。
|
||
|