# 数据库客户端组件拆分方案

## 组件架构设计

### 组件拆分

将 `index.vue` 拆分为以下组件：

1. **ConnectionTree.vue** - 左侧连接树形列表
2. **SqlEditor.vue** - SQL编辑器区域
3. **ResultPanel.vue** - 结果展示区域
4. **index.vue** - 主组件（布局和状态管理）

### 组件职责划分

#### ConnectionTree.vue
- **职责**：连接列表管理、树形结构展示、数据库/表展开
- **状态**：connections, treeData, loading, loadingNodes
- **方法**：loadConnections, loadDatabases, loadTables
- **事件**：
  - `connection-select`: 连接被选中
  - `connection-edit`: 编辑连接
  - `connection-delete`: 删除连接
  - `connection-refresh`: 需要刷新连接列表
  - `table-select`: 表被选中（用于生成SQL）
  - `new-connection`: 新建连接

#### SqlEditor.vue
- **职责**：SQL编辑器、标签页管理、工具栏
- **Props**：
  - `currentConnection`: 当前选中的连接对象
- **状态**：tabs, activeTab, editorView
- **方法**：initEditor, handleAddTab, handleDeleteTab, handleExecute, handleExecuteSelected, handleFormat
- **事件**：
  - `execute`: 执行SQL（完整内容）
  - `execute-selected`: 执行选中的SQL
  - `format`: 格式化SQL
  - `sql-insert`: 插入SQL到编辑器（由表选择触发）
  - `tab-change`: 标签页切换
  - `sql-change`: SQL内容变化

#### ResultPanel.vue
- **职责**：结果展示（表格、JSON、消息）
- **Props**：
  - `loading`: 加载状态
  - `error`: 错误信息
  - `data`: 结果数据
  - `mode`: 展示模式（table/json）
  - `stats`: 执行统计信息
  - `messages`: 消息列表
- **状态**：resultTab
- **方法**：formatJSON
- **事件**：无（纯展示组件）

#### index.vue（主组件）
- **职责**：
  - 布局管理（左侧、右侧、底部）
  - 状态协调（当前连接、执行结果）
  - 组件通信桥梁
  - 连接表单管理

### 组件通信方式

#### 1. Props 向下传递
- `currentConnection` → SqlEditor
- `loading, error, data, mode, stats, messages` → ResultPanel

#### 2. Events 向上传递
- ConnectionTree 的事件 → index.vue 处理
- SqlEditor 的事件 → index.vue 处理

#### 3. 数据流向

```
ConnectionTree
  └─ connection-select ──→ index.vue ──→ SqlEditor (currentConnection prop)
                                    └─→ ResultPanel (clear data)

SqlEditor
  └─ execute ──→ index.vue ──→ ExecuteSQL API ──→ ResultPanel (result props)

ConnectionTree
  └─ table-select ──→ index.vue ──→ SqlEditor (sql-insert event)
```

### 状态管理

#### 主组件 (index.vue) 管理的状态：
- `currentConnection`: 当前选中的连接（需要传递给 SqlEditor）
- `resultLoading, resultError, resultData, resultMode, resultStats`: 执行结果（需要传递给 ResultPanel）
- `messages`: 消息列表（需要传递给 ResultPanel）
- `showConnectionForm, editingConnectionId`: 连接表单状态

#### 子组件自己管理的状态：
- ConnectionTree: connections, treeData, loading, loadingNodes
- SqlEditor: tabs, activeTab, editorView
- ResultPanel: resultTab

### 优势

1. **职责清晰**：每个组件只关注自己的功能
2. **可维护性强**：修改某个功能只需修改对应组件
3. **可复用性**：ResultPanel 可以在其他地方复用
4. **测试友好**：每个组件可以独立测试
5. **性能优化**：可以针对单个组件进行优化

### 后续扩展

如果功能继续增加，可以考虑：
1. 引入 Pinia/Vuex 进行全局状态管理
2. 使用 provide/inject 传递深层数据
3. 提取公共逻辑到 composables

## 实现步骤

### 步骤1：创建 ConnectionTree.vue ✅
已完成，组件位置：`components/ConnectionTree.vue`

### 步骤2：创建 SqlEditor.vue
需要提取的代码：
- 编辑器相关：initEditor, editorView, tabs, activeTab
- 标签页管理：handleAddTab, handleDeleteTab
- 执行方法：handleExecute, handleExecuteSelected（通过emit传递SQL给父组件）
- 格式化：handleFormat
- SQL插入：insertSQL（用于接收表选择事件）

### 步骤3：创建 ResultPanel.vue
需要提取的代码：
- 结果展示：resultLoading, resultError, resultData, resultMode, resultStats, resultColumns
- 消息列表：messages
- 格式化：formatJSON

### 步骤4：重构 index.vue
- 移除已提取的代码
- 引入新组件
- 实现组件通信逻辑：
  - 监听 ConnectionTree 的事件
  - 调用 ExecuteSQL API
  - 传递数据到 ResultPanel

## 通信示例代码

### index.vue 中的通信代码

```vue
<template>
  <a-layout class="db-cli-layout">
    <a-layout-sider :width="280">
      <ConnectionTree
          :current-connection-id="currentConnection?.id"
          @connection-select="handleConnectionSelect"
          @connection-edit="handleConnectionEdit"
          @connection-delete="handleConnectionDelete"
          @table-select="handleTableSelect"
          @new-connection="showConnectionForm = true"
      />
    </a-layout-sider>
    
    <a-layout class="right-layout">
      <a-layout-content>
        <SqlEditor
            :current-connection="currentConnection"
            @execute="handleExecuteSQL"
            @execute-selected="handleExecuteSelectedSQL"
            @sql-insert="handleSQLInsert"
        />
      </a-layout-content>
      
      <a-layout-footer>
        <ResultPanel
            :loading="resultLoading"
            :error="resultError"
            :data="resultData"
            :mode="resultMode"
            :stats="resultStats"
            :messages="messages"
        />
      </a-layout-footer>
    </a-layout>
  </a-layout>
</template>

<script setup>
// 主组件只负责状态管理和组件协调
const currentConnection = ref(null)
const resultLoading = ref(false)
// ... 其他状态

// 连接选择
const handleConnectionSelect = (conn) => {
  currentConnection.value = conn
  // 清空结果
  clearResults()
}

// SQL执行
const handleExecuteSQL = async (sql) => {
  resultLoading.value = true
  try {
    const result = await window.go.main.App.ExecuteSQL(currentConnection.value.id, sql)
    // 处理结果，更新 resultData, resultStats 等
  } catch (error) {
    // 处理错误
  } finally {
    resultLoading.value = false
  }
}

// SQL插入
const handleSQLInsert = (sql) => {
  // 通过 ref 调用 SqlEditor 的方法
  sqlEditorRef.value?.insertSQL(sql)
}
</script>
```

