From 6bdafc3b9c2b9b6b43bc09b8a8e39bb82fc47c99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=AE=B6=E8=AE=AD?= Date: Fri, 31 Jul 2026 18:57:30 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=BE=E8=AE=A1=E5=85=AC=E5=85=B1=20UI=20?= =?UTF-8?q?=E5=9F=BA=E7=A1=80=E8=83=BD=E5=8A=9B=E6=94=B6=E5=B0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2026-07-31-public-ui-foundation-design.md | 178 ++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 docs/superpowers/specs/2026-07-31-public-ui-foundation-design.md diff --git a/docs/superpowers/specs/2026-07-31-public-ui-foundation-design.md b/docs/superpowers/specs/2026-07-31-public-ui-foundation-design.md new file mode 100644 index 0000000..d9861d7 --- /dev/null +++ b/docs/superpowers/specs/2026-07-31-public-ui-foundation-design.md @@ -0,0 +1,178 @@ +# 公共 UI 基础能力收尾设计 + +日期:2026-07-31 + +## 目标 + +收拢生成、扫描和同步类插件中重复的通知、结果文件操作、任务状态展示与无障碍语义,使窗口只负责组合界面和业务用例。重构后,常见交互具有一致行为,公共代码可以独立测试,AI 修改单个插件时不需要复制或猜测平台相关实现。 + +本阶段不改变业务流程、输出格式和历史数据格式。 + +## 范围 + +### 本阶段实施 + +- 新增统一通知入口,首批迁移 MyBatis 生成器和 Git 同步。 +- 统一 API 文档、Scanner、MyBatis SQL 导出的历史文件操作。 +- 修正 SQL 导出状态栏的无效停止按钮。 +- 加强 `ExportHistoryPane`、`EmptyStatePane`、`OperationStatusPane` 的键盘、焦点和屏幕阅读器语义。 +- 为 `ScanProgress`、`SqlExportProgress` 增加输入约束和稳定的展示转换。 +- 增加单元测试、组件测试和架构约束测试。 + +### 明确不实施 + +- Git 评审的弹窗或窗口重构。 +- 手机 UI 自动化窗口的任何重构。 +- 系统设置和插件管理窗口迁移到新通知能力。 +- 全局视觉主题、配色和窗口布局重做。 +- 为进度 DTO 引入统一继承层次或通用事件总线。 +- 把 Diff 剪贴板操作并入历史文件操作。 + +## 设计原则 + +1. 窗口不直接处理操作系统文件打开、编辑、目录定位或剪贴板细节。 +2. 公共服务通过窄接口注入,测试不启动外部程序、不写系统剪贴板。 +3. 通知文案由调用方表达业务含义,通知中心只负责展示方式和线程安全。 +4. 只有底层任务具有真实取消能力时才展示停止按钮。 +5. 不为了“统一”创建不能降低调用复杂度的抽象。 + +## 组件设计 + +### 1. NotificationCenter + +在 `system.ui.notification` 下新增: + +- `NotificationCenter`:窗口可依赖的接口。 +- `FxNotificationCenter`:JavaFX 实现,绑定 owner,并集中创建对话框。 +- `NotificationMessage`:不可变通知数据,包含级别、标题、正文;构造时拒绝空正文。 + +接口提供: + +- `info(title, message)` +- `warning(title, message)` +- `error(title, message)` +- `confirm(title, header, message)`,返回是否确认 + +普通通知允许从任意线程调用;实现会调度到 JavaFX Application Thread。确认对话框必须在 JavaFX Application Thread 调用,因为它需要同步返回用户选择;违反约束时立即抛出带说明的异常,避免后台线程静默阻塞或死锁。 + +`FxNotificationCenter` 负责 owner、默认标题、可复制长文本和一致的关闭行为。长结果仍可使用可调整大小的文本对话框,但由通知中心实现,不再由 MyBatis 窗口自行创建 `Stage`。 + +首批调用方: + +- MyBatis 生成器:查询/生成警告、生成结果、生成前确认。 +- Git 同步:缺失远程地址警告、批量重新拉取确认。 + +Git 同步中“删除目录后重新 clone”的危险说明必须原样保留;本轮只替换展示机制。 + +### 2. ResultFileActions + +在 `system.ui.history` 下新增: + +- `FileActionGateway`:`open`、`edit`、`reveal`、`copyPath` 四个操作。 +- `SystemFileActionGateway`:使用 `SystemOpenHelper` 和 JavaFX Clipboard 的生产实现。 +- `ResultFileActions`:路径校验、异常转换、统一通知和成功反馈。 + +`ResultFileActions` 可生成现有 `HistoryFileCommands`,因此 `ExportHistoryPane` 不需要知道操作系统能力,也不需要改变对外构造协议。调用方可以传入一个可选的成功消息消费者,将“已复制路径”等信息写入自己的日志区;失败统一交给 `NotificationCenter`。 + +路径规则: + +- 空路径:不调用网关,显示明确错误。 +- 打开或编辑:目标必须是存在的普通文件。 +- 定位目录:目标文件存在时定位该文件;目标已不存在时不得猜测父目录,显示错误。 +- 复制路径:复制规范化绝对路径;目标不存在时仍允许复制,以便排查历史记录,但反馈中说明目标不存在。 + +API 文档、Scanner、MyBatis SQL 导出删除各自的 `openFile`、`openWithNotepad`、`openFolder` 和剪贴板代码,改为在窗口初始化时创建一次共享命令对象。 + +### 3. 进度与取消语义 + +保留领域 DTO,不增加通用进度接口: + +- `ScanProgress`:正文不可为空;进度必须是 `-1`(不确定)或 `[0, 1]`。 +- `SqlExportProgress`:`current`、`total`、`recordCount` 不得为负,`current` 不得大于 `total`,项目名不可为空;`fraction()` 保持在 `[0, 1]`。 + +DTO 只表达领域进度。窗口通过小型纯函数把 DTO 转换为 `OperationSnapshot` 所需的 message 和 fraction,转换函数独立测试。 + +Scanner 已明确不可取消,保持不显示停止按钮。MyBatis SQL 导出的用例没有中断协议,本轮把 `OperationStatusPane` 的 `cancellable` 显式设为 `false`。不增加表面上可点击、实际上不能停止数据库或文件操作的按钮。 + +### 4. 公共组件无障碍语义 + +`ExportHistoryPane`: + +- “打开”“目录”按钮设置明确的 accessible text;tooltip 作为补充而非唯一说明。 +- 右键菜单保留,同时支持表格行获得焦点后通过键盘打开文件。 +- 行为空时清除 tooltip、accessible text 和旧行引用,避免 TableCell 复用泄漏上一个条目。 +- 操作失败后焦点留在触发控件,不强制跳转。 + +`EmptyStatePane`: + +- 容器使用可读的无障碍角色描述。 +- 标题和说明组合为完整 accessible text。 +- 有操作按钮时,按钮进入正常 Tab 顺序;无操作时容器不抢占键盘焦点。 + +`OperationStatusPane`: + +- 进度条和状态文案设置 accessible text。 +- 状态变化时同步可读文本,不只依赖颜色表达成功或失败。 +- 不可取消时,不创建可聚焦的停止按钮;可取消时只在运行阶段显示并进入 Tab 顺序。 + +本阶段用代码语义和现有主题常量检查颜色使用,不进行全主题颜色重做。若发现现有公共组件直接使用低对比硬编码颜色,只在该组件内修正。 + +## 数据与调用流 + +文件操作流程: + +`ExportHistoryPane -> HistoryFileCommands -> ResultFileActions -> FileActionGateway` + +其中 `ResultFileActions` 负责验证和错误翻译,网关只执行平台动作。窗口只提供 owner 和可选日志消费者。 + +通知流程: + +`Window / ResultFileActions -> NotificationCenter -> JavaFX dialog` + +业务异常在最接近业务语境的调用方转换成用户文案;通知中心不解析异常、不拼接业务名称,也不记录敏感值。 + +## 错误处理 + +- 公共服务捕获平台操作的已知运行时异常,展示稳定的中文动作描述,并保留异常消息作为附加信息。 +- 不吞掉编程错误:空依赖、非法 DTO 和错误线程上的确认调用立即失败。 +- 通知内容不得包含数据源密码、令牌或带凭据的远程 URL。 +- Git 重新拉取的删除与 clone 逻辑不移动到通知中心,也不因弹窗重构改变执行顺序。 + +## 测试策略 + +### 单元测试 + +- `ResultFileActionsTest`:四种委托、空路径、文件不存在、网关异常、复制不存在路径及成功反馈。 +- `NotificationMessageTest`:字段规范化和非法输入。 +- 进度 DTO 测试:边界值、非法值和 fraction。 +- 进度展示转换测试:初始、中间、结束及记录数文案。 + +### JavaFX 组件测试 + +- `ExportHistoryPane` 的按钮、tooltip、accessible text、键盘触发和 TableCell 复用清理。 +- `EmptyStatePane` 的无操作/有操作焦点行为。 +- `OperationStatusPane` 的可取消与不可取消结构、状态文字和可见性。 + +### 架构约束 + +- API 文档、Scanner、MyBatis SQL 导出不得直接调用 `SystemOpenHelper` 或 JavaFX Clipboard。 +- MyBatis 生成器和 Git 同步不得直接创建 `Alert`。 +- 排除项不纳入此约束,避免本阶段误改 Git 评审、手机 UI 自动化、系统设置。 + +### 验收 + +- 全量 Maven 测试通过。 +- Maven compile 通过。 +- `git diff --check` 通过。 +- 只读 UI 冒烟检查确认三个历史列表、MyBatis 生成确认/结果和 Git 同步确认仍可正常交互。 +- 不启动文件、编辑器、资源管理器或危险 Git 重拉操作来完成自动化验证;平台动作由测试替身验证。 + +## 实施顺序 + +1. 先以测试定义通知接口及线程约束,再实现并迁移两个窗口。 +2. 以测试定义文件动作规则,再迁移三个历史窗口。 +3. 补强进度 DTO,修正 SQL 导出取消语义。 +4. 补齐三个公共组件的无障碍行为。 +5. 运行架构测试、全量验证和只读 UI 验收。 + +每一步保持可独立编译和回滚,不把未完成的半套公共接口留给后续步骤。