# wu-mysql **Repository Path**: Innovational/wu-mysql ## Basic Information - **Project Name**: wu-mysql - **Description**: No description available - **Primary Language**: TypeScript - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-06-10 - **Last Updated**: 2026-06-14 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # WU-MySQL 一个基于 **Electron 42 + Vue 3 + TypeScript** 的 MySQL 桌面管理工具。 ## 功能概览 | 功能 | 说明 | 入口 | |------|------|------| | 连接管理 | 添加/编辑/删除连接,密码 AES-256-GCM 加密存储,连接可用性测试 | 左侧面板 `+` 按钮 | | 多连接同时打开 | 多个连接可同时保持打开,展开/收起不关闭连接,hover `x` 按钮或右键断开 | 连接树节点 hover | | 连接树搜索 | 搜索数据库/表名,模糊匹配 | 连接树顶部搜索框 | | 节点高亮 | 已连接的=蓝色加粗,选中数据库=橙色,选中表=蓝色 | 自动 | | 新建/删除数据库 | 右键连接 → 新建数据库(默认 utf8mb4)/ 删除数据库(二次确认) | 连接树右键菜单 | | 新建/删除/截断表 | 右键数据库 → 新建表;右键表 → 删除表 / 截断表(均二次确认) | 连接树/表列表右键菜单 | | 表浏览 | 点击表名自动切换到所属数据库,灰色小字显示表注释和行数,支持模糊搜索 | 左下角面板 | | 表数据查看 | 打开表默认显示数据 Tab,列头点击排序(默认倒序),空数据显示灰色"空"字,数据为空时从字段信息渲染列头 | 主区域"数据"Tab | | 刷新 | 一键刷新表字段、数据、索引、表信息 | "数据"Tab 工具栏"刷新"按钮 | | 表结构编辑 | 字段 Tab 直接增删改列,类型列支持输入+下拉建议(el-autocomplete),默认值支持 NULL/空字符串/自定义 | "字段" Tab | | 索引管理 | 索引 Tab 查看已有索引,增删改索引,索引类型可输入+选择,选择列名后自动填充索引名 | "索引" Tab | | 数据编辑 | 双击单元格编辑 → 新增行 / 删除行 → 预览 SQL → 一键保存 | "数据" Tab | | 表属性修改 | 右键表名 → 修改表名 / 修改表注释 | 表列表右键菜单 | | 自增值修改 | 表信息面板自增值可直接输入修改 | 右侧面板 | | SQL 编辑器 | 多 Tab 查询,Ctrl+Enter 执行,**支持分号 `;` 分隔批量执行多条 SQL**,编辑区/结果区高度可拖拽 | "查询" Tab | | SQL 日志 | 每次执行的 SQL 自动写入 `{userData}/sql-logs/{db}/{YYYY-MM-DD}.txt` | SQL 编辑器"打开日志"按钮 | | 数据库对比 | 右键数据库 → 选择源/目标连接和数据库 → 结构对比(含索引) → 生成同步 SQL → 一键执行 | 右键菜单"对比数据库" | | 跨连接对比 | 对比支持选择不同的源连接和目标连接 | 对比弹窗"源连接"/"目标连接"下拉 | | 数据对比 | 开发中(已禁用并提示) | — | | 表信息面板 | 查看表引擎/行数/自增值(可编辑)/排序规则/DDL 创建语句,宽度可拖拽 | 右侧面板 | ## 技术栈 | 层级 | 技术 | 说明 | |------|------|------| | 桌面壳 | Electron 42 | Chromium 148 + Node.js 24 | | 前端框架 | Vue 3.5 + vue-router 5 | Composition API + memory history | | 构建 | electron-vite 5 | 双进程热更新,输出 ESM (.mjs) | | UI 组件 | Element Plus 2.4 | 企业级中后台组件库 | | 状态管理 | Pinia 2 | 模块化 store(connection/database/query/compare) | | MySQL 驱动 | mysql2 3.x (promise API) | 连接池管理,参数化查询 | | 本地存储 | electron-store 11 | JSON 持久化,密码独立加密 | | 加密 | AES-256-GCM (Node crypto) | 密钥由 scrypt(hostname+username) 派生,不硬编码 | | 包管理 | pnpm 8+ | workspace + hoisted node_modules | | 语言 | TypeScript 5 | 全栈类型安全 | ## 环境要求 | 环境 | 最低版本 | 说明 | |------|----------|------| | Node.js | >= 18 | Electron 42 内置 Node 24 | | pnpm | >= 8 | 包管理器 | | MySQL | 5.7+ / 8.0+ | 目标数据库 | | Windows | 10+ | 开发/运行环境 | ## 快速开始 ### 1. 安装依赖 ```cmd pnpm install ``` > 首次安装时 `postinstall` 脚本会自动修补 `electron-builder` 对新版 Electron 的兼容问题。 ### 2. 开发模式运行 ```cmd rmdir /s /q out pnpm dev ``` 启动后 Electron 窗口自动打开,**开发环境**自动弹出 DevTools(生产环境不弹)。 ### 3. 浏览器调试(无需 Electron) ```cmd pnpm vite --config vite.renderer.config.ts ``` 在浏览器访问 `http://localhost:5173`,`window.electronAPI` 由 Mock 实现(仅用于 UI 调试,无法连接数据库)。 ### 4. 生产构建 ```cmd pnpm build pnpm package ``` 打包产物位于 `release/` 目录。 ## 项目结构 ``` wu-mysql/ ├── electron.vite.config.ts # electron-vite 主配置 ├── vite.renderer.config.ts # 独立 Vite 配置(浏览器调试用) ├── tsconfig.json # TS 项目引用 ├── tsconfig.node.json # 主进程/预加载 TS 配置 ├── tsconfig.web.json # 渲染进程 TS 配置 ├── .pnpmfile.cjs # pnpm hooks 声明 ├── package.json ├── scripts/ │ └── postinstall.js # 自动修补依赖(每次 pnpm install 触发) ├── .trae/ │ └── skills/wu-mysql-dev/ # IDE 开发技能(供 AI 辅助编码) ├── src/ │ ├── main/ # Electron 主进程(Node.js 环境) │ │ ├── index.ts # 入口:BrowserWindow 创建、IPC 注册、DevTools(仅开发模式) │ │ ├── ipc/ # IPC handlers(5 个文件) │ │ │ ├── connection.ts # connection:test|list|save|delete|connect|disconnect │ │ │ ├── database.ts # database:list|create|drop │ │ │ ├── table.ts # table:list|columns|data|create-sql|info|modify|rename|comment|generate-alter|create|drop|truncate|indexes|index-modify|auto-increment │ │ │ ├── query.ts # query:execute + 自动 SQL 日志记录 │ │ │ └── compare.ts # compare:schemas|cross-schemas|data │ │ ├── services/ # 业务逻辑层 │ │ │ ├── mysql-service.ts # 连接池 Map、CRUD、ALTER、索引、批量SQL │ │ │ ├── log-service.ts # SQL 审计日志(按库/日期写入 txt) │ │ │ └── compare-service.ts # 数据库对比引擎(结构+索引+数据,支持跨连接) │ │ ├── plugins/ │ │ │ └── connection-plugin.ts # electron-store 持久化(密码字段加密) │ │ └── utils/ │ │ └── crypto.ts # encrypt/decrypt (AES-256-GCM) │ ├── preload/ │ │ └── index.ts # contextBridge.exposeInMainWorld('electronAPI', {...}) — 29 个 API │ └── renderer/ # Vue3 前端(Chromium 环境) │ ├── index.html │ ├── main.ts # createApp → Pinia → Router → ElementPlus → mount + Mock API │ ├── App.vue # 根组件 + 全局样式 │ ├── env.d.ts # 所有 TS 类型声明 (window.electronAPI + 数据接口) │ ├── router/index.ts # Vue Router (memory history) │ ├── stores/ # Pinia 状态管理(4 个 store) │ │ ├── connection.ts # 连接配置 CRUD + 连接池状态 │ │ ├── database.ts # 数据库/表/字段/数据/DDL + connectionId() getter │ │ ├── query.ts # SQL 查询 Tab 管理 + executeSql 批量 │ │ └── compare.ts # 对比结果 + compareCrossSchemas() │ └── components/ # 11 个 Vue 组件 │ ├── WorkspaceLayout.vue # 三栏主布局:连接树(3/4) | 分隔条 | 表列表(1/4) + 右侧面板可拖拽 │ ├── ConnectionTree.vue # 左侧连接树(el-tree + 搜索 + 节点高亮 + 断开 x 按钮) │ ├── ConnectionDialog.vue # 连接表单弹窗(测试连接 + 保存) │ ├── TableListView.vue # 表列表(搜索 + 常显注释,右键:改表名/注释/复制) │ ├── TableDataView.vue # 字段 Tab(el-autocomplete 类型/默认值)+ 索引 Tab(增删改)+ 数据 Tab(双击编辑/增删行/刷新),flex 铺满 │ ├── TableInfoPanel.vue # 右侧面板:表信息网格(自增值可编辑)+ DDL(可复制),宽度可拖拽 │ ├── SqlEditor.vue # 查询编辑器(多 Tab,Ctrl+Enter,批量执行,编辑/结果高度可拖拽) │ ├── ResultPanel.vue # 查询结果展示(耗时/行数/el-table/错误提示) │ ├── ModifyTableDialog.vue # 字段编辑弹窗(表结构修改) │ └── CompareView.vue # 全屏对比弹窗(跨连接/索引差异/一键执行 SQL/数据对比暂禁用) ``` ## 核心架构 ### 通信链路 ``` Renderer (Chromium) Vue Component → Pinia Store → window.electronAPI.xxx() Preload (contextBridge) ipcRenderer.invoke('domain:action', ...args) Main Process (Node.js) IPC Handler → Service → mysql2/promise → MySQL Server IPC Handler → Service → logService → {userData}/sql-logs/ IPC Handler → Plugin → electron-store → {userData}/config.json ``` ### IPC 通道完整列表(29 个) | 通道 | 参数 | 返回 | 说明 | |------|------|------|------| | `connection:test` | `ConnectionConfig` | `{success, message}` | 独立连接测试可用性 | | `connection:list` | — | `ConnectionConfig[]` | 读取 electron-store | | `connection:save` | `ConnectionConfig` | `{success}` | 新建或更新,密码加密 | | `connection:delete` | `connectionId` | `{success}` | 删除配置 + 断开已有连接 | | `connection:connect` | `connectionId` | `{success, message}` | 创建连接池 | | `connection:disconnect` | `connectionId` | — | 销毁连接池 | | `database:list` | `connectionId` | `DatabaseInfo[]` | `SHOW DATABASES` + 过滤系统库 | | `database:create` | `connectionId, database, charset` | `{success}` | `CREATE DATABASE` | | `database:drop` | `connectionId, database` | `{success}` | `DROP DATABASE` | | `table:list` | `connectionId, database` | `TableInfo[]` | `information_schema.TABLES`(含注释、行数、大小)| | `table:columns` | `connectionId, database, table` | `ColumnInfo[]` | `information_schema.COLUMNS` | | `table:data` | `connectionId, database, table, page, pageSize` | `{rows, total, columns}` | `SELECT * ... LIMIT pageSize OFFSET ...` | | `table:create-sql` | `connectionId, database, table` | `string` | `SHOW CREATE TABLE` | | `table:info` | `connectionId, database, table` | `TableStatus` | `SHOW TABLE STATUS` | | `table:modify` | `connectionId, database, table, alterSql` | `{success, sql}` | 执行 ALTER TABLE | | `table:rename` | `connectionId, database, oldName, newName` | `{success}` | `RENAME TABLE` | | `table:comment` | `connectionId, database, table, comment` | `{success}` | `ALTER TABLE ... COMMENT` | | `table:generate-alter` | `connectionId, database, table, newColumns` | `SQL string` | 对比新旧字段生成 ALTER(预览,不执行)| | `table:create` | `connectionId, database, tableName` | `{success}` | `CREATE TABLE`(id 自增主键) | | `table:drop` | `connectionId, database, tableName` | `{success}` | `DROP TABLE` | | `table:truncate` | `connectionId, database, tableName` | `{success}` | `TRUNCATE TABLE` | | `table:indexes` | `connectionId, database, table` | `IndexInfo[]` | `SHOW INDEX FROM` | | `table:index-modify` | `connectionId, database, table, indexSql` | `{success, sql}` | 执行 ALTER TABLE ADD/DROP INDEX | | `table:auto-increment` | `connectionId, database, table, value` | `{success}` | `ALTER TABLE ... AUTO_INCREMENT` | | `query:execute` | `connectionId, database, sql` | `QueryResult` | **支持分号 `;` 分隔批量执行** | | `compare:schemas` | `connectionId, db1, db2` | `CompareResult` | 结构对比 + 索引对比 + 同步 SQL | | `compare:cross-schemas` | `cid1, db1, cid2, db2` | `CompareResult` | 跨连接结构对比 | | `compare:data` | `connectionId, db1, db2, table` | `CompareDataResult` | 数据对比(开发中) | | `log:open-dir` | `database` | — | `shell.openPath` 打开日志目录 | ## TypeScript 类型 所有接口定义集中在 [`src/renderer/env.d.ts`](file:///d:/wProject/wu-mysql/src/renderer/env.d.ts)。 ## 新增功能指南 1. **定义类型** — 在 `src/renderer/env.d.ts` 中新增接口和 API 签名 2. **IPC Handler** — 在 `src/main/ipc/` 新建/扩展 handler,注册到 `src/main/index.ts` 3. **Preload 桥接** — 在 `src/preload/index.ts` 中 `exposeInMainWorld` 4. **Pinia Store**(可选) — 封装业务逻辑和异步流程 5. **Vue 组件** — 实现 UI(弹窗使用 V-Model 标准模式) 详细开发指南见 [`.trae/skills/wu-mysql-dev/SKILL.md`](file:///d:/wProject/wu-mysql/.trae/skills/wu-mysql-dev/SKILL.md)。 ### V-Model 弹窗标准模式 ```typescript const props = defineProps<{ modelValue: boolean }>() const emit = defineEmits<{ (e: 'update:modelValue', v: boolean): void }>() const visible = ref(false) watch(() => props.modelValue, (v) => { if (v !== visible.value) visible.value = v }) watch(visible, (v) => { if (v !== props.modelValue) emit('update:modelValue', v) }) ``` > **不要**用 `ref(props.modelValue)` 初始化,会导致组件挂载后无法响应父组件状态变化。 ## 关键实现细节 ### el-tree 节点自定义 class ```html ``` ### 布局比例 - 连接树: `flex: 1`(占 3/4) - 表列表: `tableHeight = 225px`(拖拽范围 80~500px) - SQL 编辑器: `editorHeight = 180px`(拖拽范围 80~500px) - 右侧面板: `rightPanelWidth = 260px`(拖拽范围 180~500px) - 左侧面板: `leftWidth = 280px`(拖拽范围 200~500px) - 数据分页: 默认每页 30 条,可通过工具栏下拉切换(10/30/50/100) - 列排序: 点击列头按倒序 → 正序 → 取消排序切换(`sort-orders: ['descending', 'ascending', null]`) ## 安全说明 | 措施 | 实现 | |------|------| | 密码加密 | AES-256-GCM,密钥由 `scrypt(os.hostname() + os.userInfo().username, salt)` 派生 | | 连接管理 | `mysql2.createPool` 连接池(最多 10 个连接),连接用完自动回收 | | SQL 防注入 | 参数化查询 + 反引号转义 | | 上下文隔离 | `contextIsolation: true` + `nodeIntegration: false` | | SQL 审计 | 所有 SQL 自动记录到本地 txt,含时间戳、耗时、结果摘要 | ## 依赖补丁机制 `electron-builder 26.x` 与 `Electron 42` 存在 `ElectronDownloadCacheMode` 枚举不兼容问题。项目在 `scripts/postinstall.js` 中实现了自动修补,每次 `pnpm install` 自动执行。 ### 相关文件 | 文件 | 作用 | |------|------| | `scripts/postinstall.js` | 修补逻辑(自动查找并修改 `electronGet.js`) | | `.pnpmfile.cjs` | pnpm hooks 声明入口 | | `package.json` → `postinstall` 脚本 | lifecycle hook | | `package.json` → `build.electronDist` | 直接使用本地 Electron 跳过重复下载 | ## 操作指南 ### 连接管理 1. 点击左侧面板 `+` → 填写连接信息 → 可先点"测试连接" 2. 保存后在连接树中出现 → 点击节点打开连接 3. **支持同时打开多个连接**,已连接的显示蓝色加粗 4. hover 连接节点出现 `x` 按钮快速断开,或右键菜单选择"断开连接" 5. 连接树顶部搜索框可按数据库/表名模糊搜索 ### 管理数据库 1. 右键已连接的连接节点 → **新建数据库**(默认字符集 utf8mb4) 2. 右键数据库节点 → **删除数据库**(二次确认,不可恢复) 3. 右键数据库节点 → **新建表**(创建含 id 自增主键的空表) 4. 右键数据库节点 → 对比数据库 ### 查看表数据 1. 表列表点击表名 → **自动切换到所属数据库**,主区域**默认显示"数据" Tab**,直接查看数据 2. 点击列头排序:**第一次点击 = 倒序(DESC),第二次 = 正序(ASC),第三次 = 取消排序**;默认无排序 3. 空数据单元格显示灰色"空"字;无数据时列头从字段结构渲染,可直接新增行 4. 工具栏"刷新"按钮可一次性刷新表字段、数据、索引、表信息 5. 工具栏"每页"下拉可切换分页数(10/30/50/100),默认 30 条 6. 表列表顶部搜索框可按表名/注释模糊过滤 7. 右键表名 → 修改表名 / 修改表注释 / 截断表 / 删除表 / 复制表名 ### 编辑表结构 在"字段" Tab 中: 1. 直接修改单元格(字段名/类型/NULL/键/默认值/注释) 2. **类型列**使用 `el-autocomplete`:输入时下拉匹配,选中后值保留在输入框中可继续编辑 3. **默认值列**支持三种模式:无(清空) / `NULL (MySQL)` → `DEFAULT NULL` / `空字符串 ''` → `DEFAULT ''` / 自定义输入 4. 点击 `+ 添加字段` / `删除` 按钮 5. 点击 `预览 SQL` 查看生成的 ALTER TABLE 语句 6. 点击 `执行修改` → 确认后执行 ### 索引管理 在"索引" Tab 中: 1. 自动列出表已有的全部索引(含 PRIMARY) 2. 点击 `+ 添加索引`,选择列名后自动用列名填充索引名 3. **索引类型**使用 `el-autocomplete`(BTREE / HASH / FULLTEXT + 自定义输入) 4. 唯一开关控制 INDEX / UNIQUE INDEX 5. 点击 `预览 SQL` → `执行修改` 完成索引变更 6. PRIMARY 索引不可编辑/删除 ### 编辑数据 在"数据" Tab 中: 1. **双击**单元格进入编辑模式 → Enter 确认 / Esc 取消 2. 新增行:点击 `+ 新增行`(绿色背景) 3. 删除行:点击行末 `删除`(红色背景 + 删除线) 4. 修改行:编辑后变橙色背景 5. 点击 `保存修改(N)` → 预览 INSERT/UPDATE/DELETE SQL → 确认执行 ### SQL 编辑器 1. 切换到"查询" Tab 2. 输入 SQL,Ctrl+Enter 执行 3. **多条 SQL 用 `;` 分隔,一次性批量执行** 4. 编辑区和结果区之间的分隔条可上下拖拽调整高度 ### 数据库对比 1. 右键数据库 → "对比数据库" 2. 选择源连接/源数据库 和 目标连接/目标数据库 3. 点击"开始对比" 4. 结构对比展示字段差异 + **索引差异**(含 ADD/DROP INDEX SQL) 5. 点击"执行全部 SQL"将同步变更应用到目标库 6. 支持**跨连接对比**(如本地 MySQL vs 远程 MySQL) 7. 数据对比暂禁用(提示"开发中") ## 常见问题 ### 启动报错 "Electron uninstall" ```cmd set ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/ node node_modules/electron/install.js ``` ### 弹窗点击无反应 F12 开发者工具查 Console:`nodeClass is not a function` / `emitsOptions of null` / v-model 绑定错误。 ### SQL 提示"连接未初始化" 点击连接节点建立连接池后再执行 SQL。 ### 打包报错 "ReadWrite" `pnpm install` 自动执行 postinstall 补丁。如手动删了 node_modules: ```cmd pnpm install pnpm build && pnpm package ``` ### 连接树节点高亮无效 `el-tree` 自定义 class 必须通过 `props.class` 回调传入,不能用 `:node-class`。 ### 密码换机器后无法解密 加密密钥由 `hostname + username` 派生。换机器后需重新输入密码保存。 ## Development Skill [`.trae/skills/wu-mysql-dev/SKILL.md`](file:///d:/wProject/wu-mysql/.trae/skills/wu-mysql-dev/SKILL.md) — 包含完整架构说明、代码模式、常见 pitfalls 和新增功能指南。