8.6 KiB
公共 UI 基础能力收尾设计
日期:2026-07-31
目标
收拢生成、扫描和同步类插件中重复的通知、结果文件操作、任务状态展示与无障碍语义,使窗口只负责组合界面和业务用例。重构后,常见交互具有一致行为,公共代码可以独立测试,AI 修改单个插件时不需要复制或猜测平台相关实现。
本阶段不改变业务流程、输出格式和历史数据格式。
范围
本阶段实施
- 新增统一通知入口,首批迁移 MyBatis 生成器和 Git 同步。
- 统一 API 文档、Scanner、MyBatis SQL 导出的历史文件操作。
- 修正 SQL 导出状态栏的无效停止按钮。
- 加强
ExportHistoryPane、EmptyStatePane、OperationStatusPane的键盘、焦点和屏幕阅读器语义。 - 为
ScanProgress、SqlExportProgress增加输入约束和稳定的展示转换。 - 增加单元测试、组件测试和架构约束测试。
明确不实施
- Git 评审的弹窗或窗口重构。
- 手机 UI 自动化窗口的任何重构。
- 系统设置和插件管理窗口迁移到新通知能力。
- 全局视觉主题、配色和窗口布局重做。
- 为进度 DTO 引入统一继承层次或通用事件总线。
- 把 Diff 剪贴板操作并入历史文件操作。
设计原则
- 窗口不直接处理操作系统文件打开、编辑、目录定位或剪贴板细节。
- 公共服务通过窄接口注入,测试不启动外部程序、不写系统剪贴板。
- 通知文案由调用方表达业务含义,通知中心只负责展示方式和线程安全。
- 只有底层任务具有真实取消能力时才展示停止按钮。
- 不为了“统一”创建不能降低调用复杂度的抽象。
组件设计
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 重拉操作来完成自动化验证;平台动作由测试替身验证。
实施顺序
- 先以测试定义通知接口及线程约束,再实现并迁移两个窗口。
- 以测试定义文件动作规则,再迁移三个历史窗口。
- 补强进度 DTO,修正 SQL 导出取消语义。
- 补齐三个公共组件的无障碍行为。
- 运行架构测试、全量验证和只读 UI 验收。
每一步保持可独立编译和回滚,不把未完成的半套公共接口留给后续步骤。