# 表结构查看功能设计 **设计日期**:2026-01-28 **设计范围**:MySQL、Redis、MongoDB 表结构查看界面设计 **状态**:设计阶段 --- ## 设计概览 表结构查看功能提供统一的界面查看不同数据库类型的结构信息,支持: - **MySQL**:表字段详情、索引信息 - **MongoDB**:文档示例、字段统计、索引信息 - **Redis**:Key 类型、TTL、值预览、长度统计 **核心特性**: - 统一的对话框界面 - 根据数据库类型自动适配展示内容 - 支持 Tab 切换不同信息视图 - 表格、JSON 等多种展示方式 - 响应式设计,适配不同屏幕尺寸 --- ## 一、功能概述 表结构查看功能允许用户查看不同数据库类型的结构信息: - **MySQL**:表字段信息、索引信息 - **MongoDB**:集合文档示例、字段统计、索引信息 - **Redis**:Key 类型、TTL、值预览、长度统计 --- ## 二、界面设计 ### 2.1 触发方式 #### 方式一:连接树右键菜单(推荐) - 在连接树中,右键点击表/集合/Key节点 - 显示上下文菜单,包含"查看结构"选项 - 点击后在结果面板的"结构"Tab中展示 #### 方式二:连接树节点操作按钮 - 在表/集合/Key节点上悬停显示操作按钮 - 点击"结构"图标按钮,在结果面板展示 #### 方式三:双击节点 - 双击表/集合/Key节点,自动切换到"结构"Tab并加载结构信息 **推荐实现方式一**,用户体验最佳。 --- ### 2.2 展示位置设计 #### 在结果面板中展示 表结构信息展示在现有的 `ResultPanel` 组件中,作为第三个 Tab: ``` ┌─────────────────────────────────────────────────────────┐ │ 结果面板 │ ├─────────────────────────────────────────────────────────┤ │ [结果] [消息] [结构] │ ├─────────────────────────────────────────────────────────┤ │ [查看模式] [编辑模式] [刷新] [导出] │ ├─────────────────────────────────────────────────────────┤ │ │ │ [结构 Tab 内容区域] │ │ ┌─────────┬─────────┬─────────┐ │ │ │ 字段信息 │ 索引信息 │ 其他信息 │ │ │ └─────────┴─────────┴─────────┘ │ │ │ │ │ └─────────────────────────────────────────────────────────┘ ``` #### 模式切换 - **查看模式**(默认):只读展示,显示表结构信息 - **编辑模式**:可编辑模式,支持修改字段、添加/删除索引等操作 - **切换方式**:通过模式切换按钮或 Tab 切换 #### 展示区域属性 - **位置**:结果面板(`ResultPanel`)的第三个 Tab - **Tab 标题**:根据数据库类型显示 - MySQL: `结构 - ${database}.${table}` - MongoDB: `结构 - ${database}.${collection}` - Redis: `结构 - ${key}` - **高度**:跟随结果面板高度(可调整,默认 300px) - **滚动**:内容超出时自动滚动 #### 优势 - ✅ 无需弹出窗口,界面更简洁 - ✅ 与查询结果、消息在同一区域,操作连贯 - ✅ 可以同时查看结构信息和查询结果 - ✅ 符合现有架构,无需新增组件 --- ### 2.3 内容展示设计 #### MySQL 表结构 **Tab 1: 字段信息** ``` ┌─────────────────────────────────────────────────────────────┐ │ 字段名 │ 类型 │ 是否NULL │ 键 │ 默认值 │ 额外信息 │ ├─────────────────────────────────────────────────────────────┤ │ id │ int(11) │ NO │ PRI │ NULL │ auto_inc │ │ name │ varchar(50) │ YES │ │ NULL │ │ │ email │ varchar(100)│ NO │ UNI │ NULL │ │ │ created_at│ datetime │ NO │ │ NULL │ │ └─────────────────────────────────────────────────────────────┘ ``` **字段说明**: - **字段名**:列名 - **类型**:数据类型(int, varchar, text, datetime 等) - **是否NULL**:YES/NO - **键**:PRI(主键)、UNI(唯一键)、MUL(多键) - **默认值**:默认值或 NULL - **额外信息**:auto_increment、on update 等 **Tab 2: 索引信息** ``` ┌─────────────────────────────────────────────────────────────┐ │ 索引名 │ 唯一 │ 字段 │ 排序 │ 索引类型 │ ├─────────────────────────────────────────────────────────────┤ │ PRIMARY │ 是 │ id │ ASC │ BTREE │ │ idx_email │ 是 │ email │ ASC │ BTREE │ │ idx_name │ 否 │ name │ ASC │ BTREE │ └─────────────────────────────────────────────────────────────┘ ``` **字段说明**: - **索引名**:索引名称 - **唯一**:是/否 - **字段**:索引字段(可能有多个,用逗号分隔) - **排序**:ASC/DESC - **索引类型**:BTREE、HASH 等 --- #### MongoDB 集合结构 **Tab 1: 文档示例** ``` ┌─────────────────────────────────────────────────────────────┐ │ 文档 1 │ ├─────────────────────────────────────────────────────────────┤ │ { │ │ "_id": ObjectId("..."), │ │ "name": "John", │ │ "email": "john@example.com", │ │ "age": 30, │ │ "created_at": ISODate("2026-01-01T00:00:00Z") │ │ } │ └─────────────────────────────────────────────────────────────┘ [显示最多 5 个文档示例,JSON 格式,可折叠展开] ``` **Tab 2: 字段统计** ``` ┌─────────────────────────────────────────────────────────────┐ │ 字段名 │ 出现次数 │ 占比 │ ├─────────────────────────────────────────────────────────────┤ │ _id │ 5 │ 100% (基于5个文档示例) │ │ name │ 5 │ 100% │ │ email │ 4 │ 80% │ │ age │ 3 │ 60% │ │ created_at │ 2 │ 40% │ └─────────────────────────────────────────────────────────────┘ 文档总数: 1000 ⚠️ 字段统计基于文档示例(最多5个),仅供参考 ``` **性能分析与优化建议**: #### 当前实现分析 1. **字段统计**(当前实现): - **查询方式**:基于文档示例(最多5个)进行统计 - **性能影响**:✅ **低** - 只查询5个文档,几乎无性能影响 - **准确性**:⚠️ **不准确** - 仅基于5个文档,不能代表全表字段分布 - **适用场景**:快速预览,了解集合可能包含的字段 2. **文档总数**(当前实现): - **查询方式**:`CountDocuments({})` - 全表扫描 - **性能影响**:⚠️ **中等** - 大数据集(百万级+)可能较慢 - **优化建议**:使用 `estimatedDocumentCount()` 获取估算值(更快) #### 优化方案 **方案一:保持当前实现(推荐)** - ✅ **优点**:性能好,响应快 - ⚠️ **缺点**:字段统计不准确 - **适用**:快速预览场景,不需要精确统计 **方案二:采样统计(已确定采用)** ✅ 默认采样 10个文档 - 使用 `$sample` 聚合管道随机采样10个文档进行统计 - **性能影响**:✅ **低** - 采样10个文档,性能良好 - **准确性**:✅ **适中** - 比5个文档更准确,比全表扫描性能更好 - **实现方式**:使用 MongoDB `$sample` 聚合管道(已实现) - **异步加载**:✅ 全异步执行,不阻塞主流程 - **前端展示**:✅ 显示"基于10个文档采样统计,仅供参考" - **未来扩展**:支持可配置采样数量(P2) **方案三:全表统计(不推荐)** - 扫描所有文档统计字段 - **性能影响**:❌ **高** - 大数据集可能非常慢 - **适用**:小数据集(< 10万文档) #### 推荐实现 ```go // 方案一:保持当前实现(快速预览) // 字段统计基于文档示例(5个),性能好但准确性低 fieldStats := make(map[string]int) for _, doc := range sampleDocs { // 5个文档 for key := range doc { fieldStats[key]++ } } // 方案二:采样统计(可选,通过参数控制) // 如果用户需要更准确的统计,可以采样更多文档 if needAccurateStats { pipeline := []bson.M{ {"$sample": bson.M{"size": 1000}}, // 采样1000个文档 {"$project": bson.M{"keys": bson.M{"$objectToArray": "$$ROOT"}}}, {"$unwind": "$keys"}, {"$group": bson.M{ "_id": "$keys.k", "count": bson.M{"$sum": 1}, }}, } // 执行聚合查询... } ``` #### 前端展示建议 1. **明确标注**:字段统计显示"基于X个文档示例,仅供参考" 2. **可选刷新**:提供"精确统计"按钮,用户需要时再执行采样统计 3. **性能提示**:大数据集时提示"精确统计可能较慢" 4. **缓存策略**:字段统计结果缓存5-10分钟,避免重复查询 #### 最终建议(已确定) - **默认实现**:✅ 使用采样统计,默认采样10个文档(性能好,准确性适中) - **文档总数**:✅ 使用 `estimatedDocumentCount()` 替代 `CountDocuments()` 提升性能 - **前端展示**:明确标注"基于10个文档采样统计,仅供参考" - **后续优化**:可考虑提供"精确统计"按钮,采样更多文档(100-1000个),作为P2功能 **Tab 3: 索引信息** ``` ┌─────────────────────────────────────────────────────────────┐ │ 索引名 │ 唯一 │ 键定义 │ ├─────────────────────────────────────────────────────────────┤ │ _id_ │ 是 │ {"_id": 1} │ │ idx_email │ 是 │ {"email": 1} │ │ idx_name │ 否 │ {"name": 1, "age": -1} │ └─────────────────────────────────────────────────────────────┘ ``` --- #### Redis Key 信息 **单页展示(无 Tab)** ``` ┌─────────────────────────────────────────────────────────────┐ │ Key 信息 │ ├─────────────────────────────────────────────────────────────┤ │ Key 名称: user:1001 │ │ Key 类型: hash │ │ TTL: 3600 秒 (1 小时) │ │ 长度: 5 个字段 │ ├─────────────────────────────────────────────────────────────┤ │ 值预览: │ │ { │ │ "name": "John", │ │ "email": "john@example.com", │ │ "age": "30" │ │ } │ └─────────────────────────────────────────────────────────────┘ ``` **字段说明**: - **Key 名称**:完整的 Key 名称 - **Key 类型**:string、hash、list、set、zset 等 - **TTL**:过期时间(秒),-1 表示永不过期,-2 表示 Key 不存在 - **长度**:根据类型显示(string=字符数,hash/list/set/zset=元素数) - **值预览**:限制显示前 200 字符,过长时显示省略号 --- ## 三、组件设计 ### 3.1 组件结构 ``` ResultPanel.vue (现有组件,扩展) └── 新增 "结构" Tab ├── StructureContent.vue (结构内容组件) │ ├── 模式切换(查看/编辑) │ ├── MySQLStructure.vue (MySQL 专用) │ │ ├── ViewMode.vue (查看模式) │ │ │ ├── FieldsTab.vue (字段信息子Tab) │ │ │ └── IndexesTab.vue (索引信息子Tab) │ │ └── EditMode.vue (编辑模式) │ │ ├── FieldsEditor.vue (字段编辑表格) │ │ ├── IndexesEditor.vue (索引编辑表格) │ │ └── EditToolbar.vue (保存/取消按钮) │ ├── MongoStructure.vue (MongoDB 专用) │ │ ├── ViewMode.vue (查看模式) │ │ │ ├── SampleDocsTab.vue (文档示例子Tab) │ │ │ ├── FieldStatsTab.vue (字段统计子Tab) │ │ │ └── IndexesTab.vue (索引信息子Tab) │ │ └── EditMode.vue (编辑模式) │ │ └── IndexesEditor.vue (索引编辑,MongoDB不支持字段编辑) │ └── RedisStructure.vue (Redis 专用,仅查看模式) └── 状态管理(通过 composable) ``` ### 3.2 组件接口 #### ResultPanel.vue Props(扩展) ```typescript interface Props { // ... 现有 props structureData?: { connectionId: number database: string tableName: string dbType: 'mysql' | 'mongo' | 'redis' } | null // 表结构数据,null 表示不显示结构Tab } ``` #### 新增 Composable: useStructureState.ts ```typescript export function useStructureState() { const structureLoading = ref(false) const structureError = ref('') const structureData = ref(null) const structureInfo = ref<{ connectionId: number database: string tableName: string dbType: 'mysql' | 'mongo' | 'redis' } | null>(null) // 编辑模式相关 const editMode = ref<'view' | 'edit'>('view') const editData = ref(null) // 编辑中的数据(用于撤销) const hasChanges = ref(false) // 是否有未保存的修改 const loadStructure = async (connectionId, database, tableName, dbType) => { // 加载表结构数据 } const clearStructure = () => { structureData.value = null structureInfo.value = null editMode.value = 'view' editData.value = null hasChanges.value = false } const switchToEditMode = () => { // 切换到编辑模式,复制数据到 editData editData.value = JSON.parse(JSON.stringify(structureData.value)) editMode.value = 'edit' hasChanges.value = false } const switchToViewMode = () => { // 切换到查看模式 editMode.value = 'view' editData.value = null hasChanges.value = false } const saveStructure = async () => { // 保存结构修改,生成 ALTER TABLE 语句并执行 } return { structureLoading, structureError, structureData, structureInfo, editMode, editData, hasChanges, loadStructure, clearStructure, switchToEditMode, switchToViewMode, saveStructure } } ``` --- ## 四、数据流程 ### 4.1 数据获取流程 ``` 用户触发查看结构(右键菜单/操作按钮) ↓ ConnectionTree 触发 'table-structure' 事件 ↓ index.vue 接收事件,调用 useStructureState.loadStructure() ↓ 根据 connectionId 获取连接信息(确定 dbType) ↓ 调用 GetTableStructure API ↓ 后端根据 dbType 分发: - MySQL → GetTableStructure (DESCRIBE 查询) - MongoDB → GetCollectionStructure (文档分析) - Redis → GetKeyInfo (命令查询) ↓ 返回结构数据 ↓ 更新 structureData 和 structureInfo ↓ ResultPanel 检测到 structureInfo 不为空,显示"结构"Tab ↓ StructureContent 根据 dbType 渲染对应组件 ``` ### 4.2 API 调用 ```typescript // 获取表结构 const result = await window.go.main.App.GetTableStructure( connectionId, database, tableName ) // 返回数据结构 // MySQL: { type: 'mysql', database: 'test', table: 'users', columns: [...], // 字段信息数组 } // MongoDB: { type: 'mongo', database: 'test', collection: 'users', structure: { sampleDocs: [...], // 文档示例 fieldStats: {...}, // 字段统计 indexes: [...], // 索引信息 documentCount: 1000 // 文档总数 } } // Redis: { type: 'redis', key: 'user:1001', info: { type: 'hash', ttl: 3600, length: 5, value: {...} // 值预览 } } ``` --- ## 五、实现细节 ### 5.1 表格展示 #### 使用 Arco Design Table 组件 - **分页**:字段/索引较多时,使用分页(每页 20 条) - **排序**:支持按字段名、类型等排序 - **搜索**:字段信息表格支持搜索字段名 - **固定列**:字段名列固定,方便横向滚动查看 #### 样式优化 - **字体**:使用等宽字体显示类型信息 - **颜色**:主键字段用特殊颜色标识,NULL 字段用灰色 - **宽度**:列宽自适应,最小宽度 100px ### 5.2 JSON 展示 #### MongoDB 文档示例、Redis 值预览 - 使用 `
` 标签展示格式化的 JSON
- 支持折叠/展开(使用 `a-collapse` 组件)
- 长文本自动换行,限制最大高度,超出部分滚动
- 支持复制功能(点击复制按钮)

### 5.3 加载状态

- **加载中**:显示 Spin 组件和"加载中..."提示
- **加载失败**:显示错误提示,提供重试按钮
- **空数据**:显示空状态提示

### 5.4 响应式设计

- **小屏幕**:对话框宽度自适应,最小 600px
- **表格**:横向滚动,固定关键列
- **Tab**:内容过多时,Tab 可滚动

---

## 六、交互设计

### 6.1 触发查看结构

1. **从连接树触发**:
   - 右键菜单 → "查看结构"
   - 或点击节点操作按钮
   - 或双击节点

2. **参数传递**:
   - 从节点数据获取 `connectionId`、`database`、`tableName`、`dbType`
   - 通过事件传递给 `index.vue`
   - `index.vue` 调用 `useStructureState.loadStructure()`

3. **Tab 切换**:
   - 自动切换到结果面板的"结构"Tab
   - 如果结果面板隐藏,自动显示

### 6.2 结构Tab操作

- **切换Tab**:点击"结构"Tab查看,点击其他Tab返回
- **刷新**:在结构Tab中添加刷新按钮,重新加载结构数据
- **复制**:字段信息、索引信息支持复制(选中文本或复制按钮)
- **关闭**:切换到其他Tab或清空结构数据

### 6.3 数据更新

- **自动加载**:触发查看结构时自动加载数据
- **手动刷新**:在结构Tab中提供刷新按钮
- **错误重试**:加载失败时显示错误提示和重试按钮
- **清空数据**:切换连接或执行SQL时自动清空结构数据

---

## 七、技术实现要点

### 7.1 组件拆分

- **扩展组件**:`ResultPanel.vue` 添加"结构"Tab
- **内容组件**:`StructureContent.vue` 负责根据 `dbType` 路由到对应组件
- **专用组件**:`MySQLStructure.vue`、`MongoStructure.vue`、`RedisStructure.vue`
- **复用组件**:`IndexesTab.vue` 可被 MySQL 和 MongoDB 复用(需适配数据格式)
- **状态管理**:`useStructureState.ts` composable 管理结构数据状态

### 7.2 数据格式化

- **MySQL 字段类型**:保持原样显示(如 `int(11)`、`varchar(50)`)
- **MongoDB 文档**:BSON 转换为 JSON 格式显示
- **Redis 值**:根据类型格式化(string 直接显示,hash 显示为对象)

### 7.3 性能优化

- **懒加载**:结构Tab切换时才加载对应内容(使用 `v-if`)
- **数据缓存**:同一表结构数据缓存 5 分钟,避免重复请求
- **分页加载**:字段/索引较多时使用分页,避免一次性加载过多数据
- **按需渲染**:只有在 structureInfo 不为空时才渲染结构Tab

---

## 八、扩展功能(可选)

### 8.1 导出功能

- **导出为 SQL**:MySQL 表结构导出为 CREATE TABLE 语句
- **导出为 JSON**:MongoDB 集合结构导出为 JSON Schema
- **导出为文本**:所有类型支持导出为文本格式

### 8.2 编辑功能(融入查看区域)

#### 设计原则
- ✅ **融入查看区域**:编辑功能直接在结构查看 Tab 中实现,通过模式切换
- ✅ **统一界面**:查看和编辑使用相同的布局和组件,减少界面切换
- ✅ **权限检查**:编辑前检查用户权限(ALTER TABLE、CREATE INDEX 等)
- ✅ **操作确认**:结构修改是危险操作,需要确认对话框

#### 编辑模式设计

**模式切换**:
```
┌─────────────────────────────────────────────────────────┐
│  结构 - database.table                    [查看] [编辑] │
├─────────────────────────────────────────────────────────┤
│  [字段信息] [索引信息]                                   │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  [编辑模式内容]                                          │
│  - 可编辑表格(字段信息)                                │
│  - 添加字段按钮                                         │
│  - 删除字段按钮                                         │
│  - 保存/取消按钮                                         │
│                                                         │
└─────────────────────────────────────────────────────────┘
```

**编辑功能**:
- **MySQL**:
  - 修改字段:类型、是否NULL、默认值、注释
  - 添加字段:在指定位置添加新字段
  - 删除字段:删除不需要的字段(需确认)
  - 修改索引:添加/删除索引
- **MongoDB**:
  - 添加索引:创建新索引
  - 删除索引:删除不需要的索引(需确认)
  - 注意:MongoDB 字段是动态的,不支持字段编辑
- **Redis**:
  - 不支持编辑(Redis 是键值存储,无结构概念)

#### 实现方式

**方式一:Tab 切换(推荐)**
- 在结构 Tab 内部使用子 Tab 切换查看/编辑模式
- 查看 Tab:只读展示
- 编辑 Tab:可编辑表格,带保存/取消按钮

**方式二:按钮切换**
- 在结构 Tab 顶部添加"编辑"按钮
- 点击后切换到编辑模式,按钮变为"查看"
- 编辑模式下显示保存/取消按钮

**推荐使用方式一**,界面更清晰,模式切换更明显。

#### 编辑操作流程

```
用户点击"编辑"Tab/按钮
    ↓
检查权限(ALTER TABLE、CREATE INDEX)
    ↓
加载当前结构数据到编辑表格
    ↓
用户修改字段/索引
    ↓
点击"保存"按钮
    ↓
生成 ALTER TABLE 语句
    ↓
显示确认对话框(显示将要执行的 SQL)
    ↓
用户确认
    ↓
执行 ALTER TABLE 语句
    ↓
刷新结构数据
    ↓
切换回查看模式
```

#### 安全措施

1. **权限检查**:编辑前检查数据库用户权限
2. **确认对话框**:显示将要执行的 SQL,用户必须确认
3. **操作日志**:记录所有结构修改操作
4. **撤销功能**:支持撤销最近一次修改(可选,P2)
5. **备份提示**:重要表修改前提示备份(可选,P2)

### 8.3 对比功能

- **结构对比**:对比两个表的结构差异
- **版本历史**:记录表结构变更历史(需要额外存储)

---

## 九、实现优先级

### P0(必须实现)
1. ✅ 在 ResultPanel 中添加"结构"Tab
2. ✅ useStructureState composable 实现
3. ✅ MySQL 字段信息展示
4. ✅ MySQL 索引信息展示
5. ✅ MongoDB 文档示例展示
6. ✅ MongoDB 字段统计展示
7. ✅ Redis Key 信息展示
8. ✅ 连接树右键菜单触发

### P0.5(查看功能完成后实现)
1. 查看/编辑模式切换
2. MySQL 字段编辑(修改类型、NULL、默认值)
3. MySQL 索引编辑(添加/删除索引)
4. MongoDB 索引编辑(添加/删除索引)
5. 权限检查
6. 确认对话框

### P1(重要功能)
1. 数据加载状态和错误处理
2. JSON 格式化显示
3. 表格搜索和排序
4. 自动切换到结构Tab
5. 清空结构数据逻辑(切换连接、执行SQL时)

### P2(优化功能)
1. 数据缓存
2. 复制功能
3. 导出功能
4. 响应式优化
5. 编辑模式撤销/重做
6. 修改前备份提示

---

## 十、总结

表结构查看功能设计遵循以下原则:

1. **统一接口**:不同数据库类型使用相同的触发方式和展示框架
2. **差异化展示**:根据数据库类型展示对应的结构信息
3. **集成设计**:在结果面板中展示,无需弹出窗口,界面更简洁
4. **用户体验**:提供清晰的表格展示、JSON 格式化、搜索排序等功能
5. **性能优化**:懒加载、数据缓存、分页等优化措施
6. **可扩展性**:组件化设计,便于后续添加新功能

### 设计优势

- ✅ **无需弹出窗口**:在结果面板中展示,界面更简洁
- ✅ **操作连贯**:与查询结果、消息在同一区域,切换方便
- ✅ **符合现有架构**:扩展 ResultPanel 组件,无需新增复杂组件
- ✅ **状态管理清晰**:使用 composable 管理结构数据,易于维护
- ✅ **查看编辑融合**:编辑功能融入查看区域,通过模式切换,无需额外界面
- ✅ **统一体验**:查看和编辑使用相同布局,降低学习成本

### 编辑功能融入优势

- ✅ **无缝切换**:查看和编辑在同一区域,切换流畅
- ✅ **上下文保持**:编辑时可以看到原始结构,便于对比
- ✅ **操作连贯**:查看 → 编辑 → 保存 → 查看,流程顺畅
- ✅ **界面简洁**:不需要额外的编辑窗口或页面

通过以上设计,可以实现一个功能完善、用户体验良好的表结构查看和编辑功能。