feat: 初始化NewLife Studio项目,完成基础框架与数据管理模块
何炳宏 authored at 2026-05-26 12:09:09
16.90 KiB
NewLife.Studio
# Tasks ## Phase 1: 骨架搭建 — Task 1 ~ 2 - [ ] Task 1: 初始化解决方案与项目结构(Avalonia Studio Shell + Core + Module 接口) - [ ] `dotnet new avalonia.app` 创建 `src/App/NewLife.Studio.App`,添加 `<TargetFrameworks>net9.0</TargetFrameworks>` - [ ] `dotnet new classlib` 创建 4 个工程(按分层存放): - `src/Framework/NewLife.Studio.Core` — 无 UI 依赖的纯抽象层 - `src/Framework/NewLife.Studio.Store` — 本地持久化(依赖 Core) - `src/Providers/NewLife.Studio.Data` — 数据访问抽象(依赖 Core) - `src/Framework/NewLife.Studio.AI` — AI Provider 抽象(依赖 Core) - [ ] 定义 `src/Framework/NewLife.Studio.Core/IStudioModule.cs`: - 属性:`Id`、`DisplayName`、`Icon`、`Order` - 方法:`OnActivateAsync(CancellationToken)`、`OnDeactivateAsync(CancellationToken)`、`GetView()` → 返回 `Avalonia.Controls.Control` - [ ] 引入 NuGet 依赖: - App:`Avalonia.Desktop`、`CommunityToolkit.Mvvm`、`Microsoft.Extensions.DependencyInjection` - Core:`NewLife.Core`(日志 XTrace) - 所有项目统一使用 `System.Text.Json` 做序列化 - [ ] 实现 Shell 布局 `src/App/NewLife.Studio.App/MainWindow.axaml`: - `Grid` 三列:`NavBar`(48px) | `ModuleHost`(*) | `AIPanel`(300px, 可折叠) - `Grid` 一行:`Content`(*) | `StatusBar`(24px, 底部) - [ ] 实现 `src/App/NewLife.Studio.App/Controls/NavBar.axaml/.cs`:垂直图标列表,点击切换 Module - [ ] 实现 `src/App/NewLife.Studio.App/Controls/ModuleHost.axaml/.cs`:`ContentControl` 绑定当前激活 Module 视图 - [ ] 实现 `src/App/NewLife.Studio.App/Controls/StatusBar.axaml/.cs`:显示当前连接 / 模块名 / 后台任务 - [ ] 实现 `src/App/NewLife.Studio.App/Services/ModuleLoader.cs`: - 扫描所有已加载 Assembly 中实现 `IStudioModule` 的类型 - 按 `Order` 排序,注入导航项,激活第一个 Module - [ ] 验证:`dotnet run` 启动空 Shell 窗口,显示 NavBar/ModuleHost/StatusBar 骨架,无异常退出 - [ ] Task 2: 本地存储(连接 / 历史 / 偏好 / AI 配置) - [ ] 在 `src/Framework/NewLife.Studio.Core/DTOs/` 定义共享 DTO: - `ConnectionInfo.cs`:Id, Name, ConnectionString, ProviderType, LastUsedAt, Group - `QueryRequest.cs`:Sql, ConnectionId, MaxRows(默认1000), TimeoutSeconds(默认30) - `QueryResult.cs`:Columns[], Rows[][], RowCount, ElapsedMs, Truncated, Error - `TableInfo.cs`:Name, Schema, RowCount - `ColumnInfo.cs`:Name, DataType, IsNullable, DefaultValue, IsPrimaryKey, Ordinal - `QueryHistoryEntry.cs`:Id, Sql, ConnectionName, ExecutedAt, ElapsedMs, RowCount - [ ] 在 `src/Framework/NewLife.Studio.Store/Models/` 定义存储模型: - `StoredConnection.cs`:持久化格式(密码字段加密) - `StoredQueryHistory.cs`:JSON 行存储 - `StoredAiProfile.cs`:AiProviderType, Endpoint, ApiKey(加密), Model - `StoredAppPreference.cs`:MaxRows, DefaultExportPath, Theme, Language - [ ] 实现 `src/Framework/NewLife.Studio.Store/IStoreService.cs` 接口: - 连接 CRUD:`ListConnectionsAsync` / `SaveConnectionAsync` / `DeleteConnectionAsync` - 历史:`AddQueryHistoryAsync` / `GetRecentQueriesAsync(count)` - AI:`GetAiProfileAsync` / `SaveAiProfileAsync` - 偏好:`GetPreferencesAsync` / `SavePreferencesAsync` - [ ] 实现 `src/Framework/NewLife.Studio.Store/StoreService.cs`: - 基于 `System.Text.Json` + 本地文件(`Environment.SpecialFolder.LocalApplicationData`) - 按类型分文件:`connections.json` / `history.json` / `ai_profile.json` / `preferences.json` - [ ] 实现 `src/Framework/NewLife.Studio.Store/SecretProtection.cs`: - `Protect(string plain)` / `Unprotect(string cipher)` — AES 加密 - 连接保存时自动加密密码、AI Key 字段 - [ ] 注册:`services.AddSingleton<IStoreService, StoreService>()` - [ ] 验证:写入连接 → 重启 → 读取仍存在;密码字段在文件中不可明文读取 --- ## Phase 2: Data Studio 核心 — Task 3 ~ 4 - [ ] Task 3: Data Studio — SQLite Provider(会话与元数据) - [ ] 定义 `src/Providers/NewLife.Studio.Data/IDataProvider.cs`: - `ProviderName`、`SupportedSchemes[]`、`CanTestConnection` - `TestConnectionAsync(ConnectionInfo, CancellationToken)` → `Task<bool>` - `OpenSessionAsync(ConnectionInfo, CancellationToken)` → `Task<IDbSession>` - [ ] 定义 `src/Providers/NewLife.Studio.Data/IDbSession.cs`: - `SessionId`、`Connection`、`IsOpen` - `GetTablesAsync(CancellationToken)` → `Task<TableInfo[]>` - `GetColumnsAsync(string tableName, CancellationToken)` → `Task<ColumnInfo[]>` - `ExecuteQueryAsync(QueryRequest, CancellationToken)` → `Task<QueryResult>` - `CloseAsync()` - 继承 `IDisposable` - [ ] 实现 `src/Providers/NewLife.Studio.Data/Providers/SQLite/SQLiteProvider.cs`: - `ProviderName = "SQLite"`,`SupportedSchemes = ["sqlite", "sqlite3"]` - `TestConnectionAsync`:打开 `Microsoft.Data.Sqlite.SqliteConnection` → 执行 `SELECT 1` → 关闭 - `OpenSessionAsync`:创建并返回 `SQLiteSession` 实例 - [ ] 实现 `src/Providers/NewLife.Studio.Data/Providers/SQLite/SQLiteSession.cs`: - 持有 `Microsoft.Data.Sqlite.SqliteConnection` - `CloseAsync` → `connection.Close()` + `Dispose()` - `GetTablesAsync` → 查询 `sqlite_master WHERE type='table' ORDER BY name` - `GetColumnsAsync` → 使用 `PRAGMA table_info('{tableName}')` - `ExecuteQueryAsync` → 委托给 Task 4 - [ ] 实现 `src/Providers/NewLife.Studio.Data/Providers/SQLite/SQLiteMetadataReader.cs`: - 解析 `PRAGMA table_info` 结果 → `ColumnInfo[]` - 解析 `PRAGMA index_list` + `PRAGMA index_info` → 索引信息 - 解析 `PRAGMA foreign_key_list` → 外键信息(可为空列表) - [ ] 注册:`services.AddSingleton<IDataProvider, SQLiteProvider>()`(后续多 Provider 改为工厂) - [ ] 验证:打开测试 SQLite 文件,列表出所有表,每张表可展开列信息 - [ ] Task 4: Data Studio — 查询执行与结果模型 - [ ] 确认 Core DTO `QueryRequest` / `QueryResult` 字段完整(已在 Task 2 定义) - [ ] 在 `SQLiteSession.ExecuteQueryAsync` 中实现: - 创建 `SqliteCommand`,设置 `CommandTimeout = request.TimeoutSeconds` - 使用 `ExecuteReaderAsync` + `CancellationToken` 实现取消 - 逐行读取,达到 `MaxRows` 时停止并标记 `Truncated = true` - 记录 `ElapsedMs = Stopwatch` 耗时 - [ ] 结果封装为 `QueryResult`: - `Columns` 从 `reader.GetSchemaTable()` 提取 - `Rows` 为 `List<object[]>`,每个 cell 使用 `reader.GetValue(i)` 取原始值 - 异常时设置 `Error` 字段并返回空结果 - [ ] 实现历史记录写入: - 依赖注入 `IStoreService` - 查询成功或失败均异步写入 `QueryHistoryEntry`(不阻塞 UI) - [ ] 验证:执行 `SELECT * FROM some_table` → 返回网格数据,耗时可见,超限行数被裁剪 --- ## Phase 3: Data Studio UI — Task 5 ~ 6 - [ ] Task 5: Data Studio — UI(MVP 闭环) - [ ] 创建 Module 项目 `src/Modules/DataStudio/`(作为独立 `classlib`,引用 Avalonia + Core + Store + Data) - [ ] 实现 `DataStudioModule.cs : IStudioModule`: - `Id = "data-studio"`,`DisplayName = "数据管理"`,`Order = 0` - `GetView()` → new `DataStudioView` - [ ] 实现 `DataStudioViewModel`(主 ViewModel,持有子 ViewModel 引用) - [ ] 实现 `src/Modules/DataStudio/ViewModels/ConnectionListViewModel.cs`: - `ObservableCollection<ConnectionInfo> Connections` - `AddConnectionCommand` → 弹出对话框输入 Name / FilePath → 调用 `IStoreService.SaveConnectionAsync` - `EditConnectionCommand` / `DeleteConnectionCommand` - `TestConnectionCommand` → 调用 `IDataProvider.TestConnectionAsync` → 显示成功/失败提示 - `OpenConnectionCommand` → 调用 `IDataProvider.OpenSessionAsync` → 传入 ObjectTreeVM - [ ] 实现 `src/Modules/DataStudio/Views/ConnectionListView.axaml/.cs`: - `ListBox` 绑定 `Connections`,每项显示 Name + 最近使用时间 - ToolBar 按钮:`+ 新建` `测试` `编辑` `删除` - [ ] 实现 `src/Modules/DataStudio/ViewModels/ObjectTreeViewModel.cs`: - `ObservableCollection<TreeNode> Nodes`(连接→Table→Column 递归树) - `ExpandTableCommand` → 调用 `IDbSession.GetColumnsAsync` → 填充子节点 - 选中表时触发 `TableSelected` 事件 - [ ] 实现 `src/Modules/DataStudio/Views/ObjectTreeView.axaml/.cs`: - `TreeView` 绑定 `Nodes`,HierarchicalDataTemplate 渲染三层 - [ ] 实现 `src/Modules/DataStudio/ViewModels/SqlEditorViewModel.cs`: - `ObservableCollection<QueryTab> Tabs`(每个 Tab 有 Sql 文本框 + Result) - `ExecuteCommand` → 构建 `QueryRequest` → 调用 `IDbSession.ExecuteQueryAsync` → 更新 `Result` - `NewTabCommand` / `CloseTabCommand` - [ ] 实现 `src/Modules/DataStudio/Views/SqlEditorView.axaml/.cs`: - `TabControl` 绑定 `Tabs`,每个 Tab 内含 `TextBox`(SQL 编辑) + `Button`(执行) - [ ] 实现 `src/Modules/DataStudio/ViewModels/ResultGridViewModel.cs`: - `Columns` / `Rows` 绑定到 DataGrid - `ElapsedMs` / `RowCount` / `TruncatedWarning` 显示 - `ExportCsvCommand` / `ExportJsonCommand`(委托 Task 6) - [ ] 实现 `src/Modules/DataStudio/Views/ResultGridView.axaml/.cs`: - `DataGrid` 自动列生成(AutoGenerateColumns=True) - 底部显示耗时 + 行数 + 裁剪提示 - [ ] 在 App 启动时注册 DataStudioModule: - `ModuleLoader` 扫描到 `DataStudioModule`,添加 NavBar 图标,默认激活 - [ ] 验证:完整 UI 交互闭环(新建连接 → 打开 → 浏览表 → 执行 SQL → 看结果) - [ ] Task 6: Data Studio — 导出(CSV / JSON) - [ ] 在 `ResultGridViewModel` 中实现: - `ExportCsvAsync(string filePath)`: - 使用 `StreamWriter` + UTF-8 BOM - 首行写入列名(逗号分隔),值含逗号/引号时加双引号转义 - 逐行写入数据行 - `ExportJsonAsync(string filePath)`: - 使用 `System.Text.Json` 序列化 - 格式:`[{ "col1": val1, "col2": val2 }, ...]` - [ ] UI 层: - 结果区 ToolBar 添加 `导出 CSV` / `导出 JSON` 按钮 - 点击弹出 `SaveFileDialog`(Avalonia `StorageProvider`)选择保存路径 - [ ] 验证:查询结果导出为 CSV → 用记事本/Excel 打开 → 列正确无乱码;导出为 JSON → 格式合法 --- ## Phase 4: AI 助手 — Task 7 - [ ] Task 7: AI 助手(Provider 可插拔 + Tool Calling MVP) - [ ] 定义 `src/Framework/NewLife.Studio.AI/IAiProvider.cs`: - `ProviderName` - `ChatAsync(ChatRequest, CancellationToken)` → `Task<ChatResponse>` - [ ] 定义 AI 模型 DTO `src/Framework/NewLife.Studio.AI/Models/`: - `ChatMessage.cs`:Role, Content, ToolCalls[], ToolCallId - `ChatRequest.cs`:Messages[], Tools[], Model, MaxTokens - `ChatResponse.cs`:Content, ToolCalls[], InputTokens, OutputTokens - `ToolCall.cs`:Id, Name, Arguments(JSON) - `ToolResult.cs`:ToolCallId, Output, Error - `ToolDefinition.cs`:Name, Description, Parameters(JSON Schema) - [ ] 实现 `src/Framework/NewLife.Studio.AI/AiProviderFactory.cs`: - 根据 `AiProfile.ProviderType`("openai"/"azure"/"ollama")创建对应 `IAiProvider` - [ ] 实现 OpenAI Provider(首个实现): - HttpClient 调用 `https://api.openai.com/v1/chat/completions` - 支持 Tool Calling(tools 参数传递) - 解析响应中的 `tool_calls` 与 `content` - [ ] 实现 `src/Framework/NewLife.Studio.AI/ToolCalling/ToolRegistry.cs`: - `Register(string name, Func<string, Task<string>> handler, ToolDefinition definition)` - `GetAllDefinitions()` → `ToolDefinition[]` - [ ] 实现 `src/Framework/NewLife.Studio.AI/ToolCalling/ToolExecutor.cs`: - `ExecuteAsync(ToolCall call)` → `Task<ToolResult>` - 通过 `ToolRegistry` 查找 handler,执行并返回结果 - [ ] 实现 6 个内置工具 `src/Framework/NewLife.Studio.AI/ToolCalling/BuiltInTools/`: | 工具名 | 功能 | |---|---| | `connections.list` | 列出所有已保存的连接(脱敏) | | `db.open` | 打开指定数据库连接,返回会话 ID | | `schema.tables` | 列出当前会话的表 | | `schema.table` | 查看指定表的列详情 | | `query.select` | 执行 SELECT(经安全过滤) | | `query.sample` | 取表的前 N 行样本数据 | - [ ] 实现 `src/Framework/NewLife.Studio.AI/Safety/QuerySafetyFilter.cs`: - 仅允许 `SELECT` / `EXPLAIN` / `PRAGMA` 开头的语句 - 拒绝所有写操作(INSERT/UPDATE/DELETE/DROP/ALTER/CREATE) - 拒绝多语句(分号分隔) - 超行限制 + 超时取消 - [ ] 实现 Shell 级 AI 面板 `src/App/NewLife.Studio.App/Controls/AIPanel.axaml/.cs`: - `ChatMessageList`:`ItemsControl` 渲染对话气泡(User 右对齐蓝底,Assistant 左对齐灰底,Tool 灰底斜体) - Markdown 渲染(简单实现:支持 ``` 代码块和纯文本) - `ToolCallInfo`:可展开区域,显示工具名 + 参数 + 返回结果 - `ChatInput`:多行 `TextBox` + `Button`("发送") - [ ] 实现 `AIService`(跨 Module 共享): - 管理对话历史 `List<ChatMessage>` - 实现 Tool Calling 循环:发送 → 检测 tool_calls → 执行工具 → 追加结果 → 再发送 - [ ] 在 AI Profile 未配置时,AI Panel 显示引导提示"请先配置 AI 服务" - [ ] 验证:AI 分析数据库完整闭环(列出表 → 查看结构 → 执行样本查询 → 输出分析汇总) --- ## Phase 5: 打包验证 — Task 8 - [ ] Task 8: 打包与基本验证 - [ ] 端到端集成验证: 1. `dotnet run` → Shell 窗口启动 → NavBar 显示"数据管理"图标 2. 新建 SQLite 连接 → 测试连接成功 → 打开连接 3. 对象树展开 Table 列表 → 点击表查看列信息 4. SQL 编辑器输入 `SELECT * FROM table LIMIT 10` → 执行 → 结果网格显示 5. 导出 CSV / JSON → 文件内容正确 6. 打开 AI 面板 → 输入"分析数据库结构" → AI 调用工具 → 输出分析 7. AI 尝试 `INSERT INTO` → 被拒绝 → 显示错误提示 8. 关闭应用 → 重新启动 → 连接/历史/偏好仍存在 - [ ] 验证 `IStudioModule` 可扩展性: - 编写一个 Mock Module 实现 `IStudioModule`,编译为独立 dll 放入 App 目录 - 启动后 NavBar 出现该模块图标,点击可切换视图 - [ ] 跨平台发布配置: - `dotnet publish -c Release -r win-x64 --self-contained` → 生成 Windows 产物 - `dotnet publish -c Release -r linux-x64 --self-contained` → 生成 Linux 产物 - `dotnet publish -c Release -r osx-x64 --self-contained` → 生成 macOS 产物 - 验证:三个平台的发布产物均可启动(解压即用) --- # Task Dependencies ``` Task 1 (Shell + Module接口) ├──► Task 2 (Store) │ └──► Task 4 (查询执行) │ └──► Task 5 (UI) │ └──► Task 6 (导出) │ └──► Task 3 (SQLite Provider) └──► Task 4 ──► Task 5 ──► Task 6 │ Task 7 (AI) ────────────┤ (依赖 Task 1,2,3,4) │ │ Task 8 (打包) ───────────┘ (依赖 Task 5,6,7) ``` - Task 2 depends on Task 1 - Task 3 depends on Task 1 - Task 4 depends on Task 3 and Task 2 - Task 5 depends on Task 1, Task 2, Task 3, and Task 4 - Task 6 depends on Task 4 and Task 5 - Task 7 depends on Task 1, Task 2, Task 3, and Task 4 - Task 8 depends on Task 5, Task 6, and Task 7 --- # Module Expansion Roadmap(后续迭代参考) - Task 9: MQTT Studio 模块 - `src/Providers/NewLife.Studio.Mqtt/` — MQTT 客户端封装 - `src/Modules/MqttStudio/` — 连接 MQTT Broker(NewLife.MQTT) - Topic 树浏览、消息发布/订阅 - 客户端连接状态监控 - Task 10: MQ Studio 模块 - `src/Providers/NewLife.Studio.Mq/` — 消息队列抽象 - `src/Modules/MqStudio/` — MQ 队列管理 - MQ 队列列表(NewLife.MQ / NewLife.RocketMQ) - 消息查看、消费状态、堆积监控 - Task 11: Redis Studio 模块 - `src/Providers/NewLife.Studio.Redis/` — Redis 客户端封装 - `src/Modules/RedisStudio/` — Key 浏览与搜索 - Key 浏览与搜索(NewLife.Redis) - 命令执行控制台、内存/命中率监控 - Task 12: Stardust Console 模块 - `src/Modules/StardustConsole/` — 星尘平台管理 - 星尘平台节点/应用/配置总览(NewLife.Stardust) - APM 调用链查看、日志搜索 - Task 13: Modbus Studio 模块 - `src/Providers/NewLife.Studio.Modbus/` — Modbus 协议封装 - `src/Modules/ModbusStudio/` — Modbus 设备管理 - Modbus 设备扫描、寄存器读写(NewLife.Modbus / NewLife.IoT)