# 架构改进方案：状态管理优化

## 问题分析

当前遇到的问题属于"响应式状态同步灾难"，主要问题：

1. **状态分散**：多个 Composables 各自管理状态，难以追踪数据流
2. **响应式失效**：computed/watch 在复杂场景下失效，难以调试
3. **数据传递复杂**：props/computed/provide 多层传递，容易丢失
4. **缺乏状态快照**：无法回溯状态变化历史
5. **调试困难**：大量 console.log 散布在代码中，难以系统化

## 改进方案

### 1. 引入 Pinia 统一状态管理

#### 1.1 安装 Pinia

```bash
npm install pinia
```

#### 1.2 创建 Store 结构

```
stores/
  ├── db-cli/
  │   ├── index.ts          # 主 store
  │   ├── connection.ts     # 连接状态
  │   ├── structure.ts      # 表结构状态
  │   ├── result.ts         # 查询结果状态
  │   ├── editor.ts         # 编辑器状态
  │   └── message.ts        # 消息日志状态
  └── devtools.ts           # 开发工具（状态快照/回放）
```

#### 1.3 核心 Store 设计

**stores/db-cli/structure.ts** - 表结构状态管理

```typescript
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'

export interface StructureInfo {
  connectionId: number
  database: string
  tableName: string
  dbType: 'mysql' | 'mongo' | 'redis'
  nodeType: string
}

export interface StructureData {
  type: string
  columns?: any[]
  database?: string
  table?: string
  // ... 其他字段
}

export const useStructureStore = defineStore('structure', () => {
  // 状态定义
  const loading = ref(false)
  const error = ref<string | null>(null)
  const data = ref<StructureData | null>(null)
  const info = ref<StructureInfo | null>(null)
  
  // 计算属性（自动响应式）
  const hasData = computed(() => data.value !== null && info.value !== null)
  const isReady = computed(() => !loading.value && hasData.value)
  
  // Actions（统一的数据变更入口）
  async function loadStructure(params: {
    connectionId: number
    database: string
    tableName: string
    dbType: 'mysql' | 'mongo' | 'redis'
    nodeType: string
  }) {
    // 防止重复加载
    if (loading.value) {
      console.warn('结构正在加载中，跳过重复请求')
      return
    }
    
    try {
      loading.value = true
      error.value = null
      
      // 验证参数
      if (params.nodeType === 'connection' || params.nodeType === 'database') {
        info.value = {
          ...params,
          tableName: ''
        }
        data.value = null
        return
      }
      
      if (!params.tableName) {
        info.value = {
          ...params,
          tableName: ''
        }
        data.value = null
        return
      }
      
      // 调用后端
      if (!window.go?.main?.App?.GetTableStructure) {
        throw new Error('Go 后端未就绪')
      }
      
      const result = await window.go.main.App.GetTableStructure(
        params.connectionId,
        params.database,
        params.tableName
      )
      
      // 原子性更新（确保数据一致性）
      data.value = result
      info.value = params
      
      // 状态变更日志（开发环境）
      if (import.meta.env.DEV) {
        console.log('[StructureStore] 数据加载成功', { info: params, data: result })
      }
    } catch (err) {
      const errorMessage = err instanceof Error ? err.message : '加载表结构失败'
      error.value = errorMessage
      data.value = null
      info.value = null
      
      if (import.meta.env.DEV) {
        console.error('[StructureStore] 加载失败', err)
      }
    } finally {
      loading.value = false
    }
  }
  
  function clear() {
    data.value = null
    info.value = null
    error.value = null
  }
  
  function reset() {
    loading.value = false
    error.value = null
    data.value = null
    info.value = null
  }
  
  return {
    // 状态
    loading,
    error,
    data,
    info,
    // 计算属性
    hasData,
    isReady,
    // 方法
    loadStructure,
    clear,
    reset
  }
})
```

**stores/db-cli/index.ts** - 主 Store

```typescript
import { defineStore } from 'pinia'
import { useStructureStore } from './structure'
import { useConnectionStore } from './connection'
// ... 其他 stores

// 组合 Store，提供统一访问入口
export const useDbCliStore = () => {
  return {
    structure: useStructureStore(),
    connection: useConnectionStore(),
    // ... 其他 stores
  }
}
```

### 2. 组件中使用 Store

**views/db-cli/index.vue**

```typescript
<script setup lang="ts">
import { useStructureStore } from '@/stores/db-cli/structure'

// 使用 Store（自动响应式，无需 computed）
const structureStore = useStructureStore()

// 直接使用，Vue 会自动追踪
const handleTableStructure = async (data: TableStructureEvent) => {
  // 单一切口，清晰的数据流
  await structureStore.loadStructure({
    connectionId: data.connectionId,
    database: data.database,
    tableName: data.tableName,
    dbType: data.dbType,
    nodeType: data.nodeType
  })
  
  // 切换到结构 Tab
  if (resultPanelRef.value) {
    resultPanelRef.value.switchToStructureTab()
  }
}
</script>

<template>
  <ResultPanel
    :structure-loading="structureStore.loading"
    :structure-error="structureStore.error"
    :structure-data="structureStore.data"
    :structure-info="structureStore.info"
  />
</template>
```

### 3. 状态调试工具

**stores/devtools.ts** - 开发工具

```typescript
import { watch } from 'vue'

/**
 * 状态变更追踪器（仅开发环境）
 */
export function setupStateDebugger() {
  if (!import.meta.env.DEV) return
  
  // 追踪所有 store 的状态变更
  const stateHistory: Array<{
    timestamp: number
    store: string
    action: string
    oldValue: any
    newValue: any
  }> = []
  
  return {
    log(store: string, action: string, oldValue: any, newValue: any) {
      stateHistory.push({
        timestamp: Date.now(),
        store,
        action,
        oldValue: JSON.parse(JSON.stringify(oldValue)),
        newValue: JSON.parse(JSON.stringify(newValue))
      })
      
      console.group(`[${store}] ${action}`)
      console.log('旧值:', oldValue)
      console.log('新值:', newValue)
      console.log('历史记录:', stateHistory.slice(-10))
      console.groupEnd()
    },
    
    getHistory() {
      return stateHistory
    },
    
    clearHistory() {
      stateHistory.length = 0
    }
  }
}
```

### 4. 类型安全增强

**types/db-cli.ts**

```typescript
// 统一类型定义
export type DbType = 'mysql' | 'mongo' | 'redis'
export type NodeType = 'connection' | 'database' | 'table' | 'collection' | 'key'

export interface ConnectionInfo {
  id: number
  name: string
  type: DbType
  host: string
  port: number
  database?: string
}

export interface StructureInfo {
  connectionId: number
  database: string
  tableName: string
  dbType: DbType
  nodeType: NodeType
}

// 严格类型检查
export function assertStructureInfo(info: unknown): asserts info is StructureInfo {
  if (!info || typeof info !== 'object') {
    throw new Error('Invalid StructureInfo')
  }
  // ... 类型检查逻辑
}
```

### 5. 状态持久化策略

```typescript
// stores/db-cli/structure.ts
import { defineStore } from 'pinia'
import { useStorage } from '@vueuse/core'

export const useStructureStore = defineStore('structure', () => {
  // 使用 localStorage 持久化（可选）
  const lastStructureInfo = useStorage<StructureInfo | null>(
    'db-cli-last-structure-info',
    null
  )
  
  // 恢复上次查看的结构
  function restoreLastStructure() {
    if (lastStructureInfo.value) {
      loadStructure(lastStructureInfo.value)
    }
  }
  
  // 在 loadStructure 中保存
  async function loadStructure(params: StructureInfo) {
    // ... 加载逻辑
    info.value = params
    lastStructureInfo.value = params // 自动保存到 localStorage
  }
  
  return { /* ... */ }
})
```

### 6. 错误边界和恢复机制

```typescript
// stores/db-cli/structure.ts
export const useStructureStore = defineStore('structure', () => {
  const retryCount = ref(0)
  const maxRetries = 3
  
  async function loadStructure(params: StructureInfo, retry = 0) {
    try {
      // ... 加载逻辑
      retryCount.value = 0 // 成功后重置
    } catch (err) {
      if (retry < maxRetries) {
        console.warn(`[StructureStore] 重试加载 (${retry + 1}/${maxRetries})`)
        await new Promise(resolve => setTimeout(resolve, 1000 * (retry + 1)))
        return loadStructure(params, retry + 1)
      }
      // 超过重试次数，记录错误
      error.value = `加载失败（已重试 ${maxRetries} 次）: ${err}`
    }
  }
  
  return { /* ... */ }
})
```

### 7. 组件级状态同步检查

```typescript
// composables/useStateSync.ts
import { watch, nextTick } from 'vue'

/**
 * 状态同步检查器
 * 确保 Store 状态和组件 props 保持同步
 */
export function useStateSync<T>(
  storeValue: () => T,
  propValue: () => T,
  name: string
) {
  if (!import.meta.env.DEV) return
  
  watch(
    () => storeValue(),
    (storeVal) => {
      nextTick(() => {
        const propVal = propValue()
        if (storeVal !== propVal) {
          console.error(
            `[StateSync] ${name} 不同步！`,
            `Store: ${JSON.stringify(storeVal)}`,
            `Prop: ${JSON.stringify(propVal)}`
          )
        }
      })
    },
    { deep: true }
  )
}
```

### 8. 测试策略

```typescript
// stores/db-cli/structure.test.ts
import { setActivePinia, createPinia } from 'pinia'
import { useStructureStore } from './structure'

describe('StructureStore', () => {
  beforeEach(() => {
    setActivePinia(createPinia())
  })
  
  it('应该正确加载结构数据', async () => {
    const store = useStructureStore()
    
    await store.loadStructure({
      connectionId: 1,
      database: 'test',
      tableName: 'users',
      dbType: 'mysql',
      nodeType: 'table'
    })
    
    expect(store.loading).toBe(false)
    expect(store.data).not.toBeNull()
    expect(store.info).not.toBeNull()
  })
  
  it('应该在加载失败时设置错误', async () => {
    // ... 测试错误处理
  })
})
```

## 迁移步骤

1. **阶段一：引入 Pinia**
   - 安装依赖
   - 创建基础 Store 结构
   - 在主应用初始化 Pinia

2. **阶段二：迁移状态**
   - 先迁移 structure store（当前问题所在）
   - 逐步迁移其他 stores
   - 保持双写一段时间（Composable + Store）

3. **阶段三：清理代码**
   - 移除旧的 Composables
   - 统一使用 Store
   - 添加类型定义

4. **阶段四：优化和测试**
   - 添加状态调试工具
   - 编写单元测试
   - 性能优化

## 优势总结

1. **单一数据源**：所有状态集中在 Store，避免分散
2. **自动响应式**：Pinia 自动处理响应式，无需手动 computed
3. **开发工具**：Pinia DevTools 可以可视化状态变化
4. **类型安全**：TypeScript 支持更好
5. **易于测试**：Store 可以独立测试
6. **状态持久化**：内置支持 localStorage/sessionStorage
7. **调试友好**：可以回放状态变更历史

## 注意事项

1. **不要过度使用**：简单的局部状态仍可使用 ref/reactive
2. **避免循环依赖**：Store 之间不要相互依赖
3. **性能考虑**：大数据量使用 shallowRef
4. **SSR 兼容**：如需 SSR，注意状态初始化

## 参考资料

- [Pinia 官方文档](https://pinia.vuejs.org/)
- [Vue 3 Composition API 最佳实践](https://vuejs.org/guide/extras/composition-api-faq.html)
