feat: 微信 AI 助手插件(wechat-ai)基线
- 移除旧 aitest 与 mobile-ui-auto 插件及其资源、测试 - 新增纯 Java 微信 AI 助手插件(ADB 驱动 + AI 回复) - 同步更新主界面图标映射、主题样式与插件配置
This commit is contained in:
@@ -0,0 +1,218 @@
|
||||
---
|
||||
name: wechat-ai-helper-plugin
|
||||
overview: 删除现有 mobile-ui-auto 手机 UI 自动化插件(含 Python/Airtest 依赖),全新编写纯 Java 的"微信 AI 助手"插件:通过 ADB 读取安卓微信聊天记录、监测指定联系人的新消息,并按用户配置的话术由大模型 AI 自动/半自动回复。
|
||||
design:
|
||||
styleKeywords:
|
||||
- 深色科技
|
||||
- 卡片化面板
|
||||
- 状态徽标
|
||||
- 分栏布局
|
||||
- 克制动效
|
||||
- 高对比可读性
|
||||
fontSystem:
|
||||
fontFamily: Microsoft YaHei UI
|
||||
heading:
|
||||
size: 20px
|
||||
weight: 600
|
||||
subheading:
|
||||
size: 15px
|
||||
weight: 600
|
||||
body:
|
||||
size: 13px
|
||||
weight: 400
|
||||
colorSystem:
|
||||
primary:
|
||||
- "#4F8CFF"
|
||||
- "#00C9A7"
|
||||
background:
|
||||
- "#181D26"
|
||||
- "#1E2430"
|
||||
- "#262D3B"
|
||||
text:
|
||||
- "#E8ECF4"
|
||||
- "#9AA5B8"
|
||||
- "#FFFFFF"
|
||||
functional:
|
||||
- "#27AE60"
|
||||
- "#EB5757"
|
||||
- "#F2994A"
|
||||
- "#56CCF2"
|
||||
todos:
|
||||
- id: remove-old-plugin
|
||||
content: 用 [mcp:Windows CLI MCP Server] 删除旧 mobile-ui-auto 代码/资源/data 目录,并用 [subagent:code-explorer] 复核引用点后同步更新 plugins.config、MainWindow 图标映射与插件测试
|
||||
status: completed
|
||||
- id: adb-wechat-reader
|
||||
content: 实现 AdbClient 与 WechatSessionReader,完成设备连接、微信启动、dump 解析与聊天记录读取
|
||||
status: completed
|
||||
dependencies:
|
||||
- remove-old-plugin
|
||||
- id: monitor-ai-engine
|
||||
content: 实现 MessageMonitor 快照比对监测与 AiResponder 模板命中+AI 生成,含 config.json 持久化
|
||||
status: completed
|
||||
dependencies:
|
||||
- adb-wechat-reader
|
||||
- id: wechat-ai-ui
|
||||
content: 实现 WechatAiWindow 四页签界面与 WechatAiPlugin 注册,整合联系人/话术/AI 配置与监控日志
|
||||
status: completed
|
||||
dependencies:
|
||||
- monitor-ai-engine
|
||||
- id: compile-verify
|
||||
content: 用 [mcp:Windows CLI MCP Server] 执行 mvnw compile 并启动应用,验证插件加载、配置生效与旧插件消失
|
||||
status: completed
|
||||
dependencies:
|
||||
- wechat-ai-ui
|
||||
---
|
||||
|
||||
## 产品概述
|
||||
|
||||
将现有"手机UI自动化"插件(基于 Python/Airtest 的测试工具)整体删除重写,全新打造"微信AI助手"插件(方案C)。插件通过 ADB 连接安卓手机微信,实现聊天记录读取、指定联系人消息监测、AI 按用户话术自动回复三大能力,纯 Java 实现、无 Python 依赖。
|
||||
|
||||
## 核心功能
|
||||
|
||||
- **设备连接与微信启动**:USB/无线 ADB 设备枚举与连接,一键启动手机微信,前台状态检测。
|
||||
- **聊天记录读取**:`uiautomator dump` 提取消息文本节点(精确免费),支持滚动加载历史记录;截图保存作为视觉兜底,可识别图片消息。
|
||||
- **指定联系人监测**:维护"指定人"名单,定时轮询会话最新消息与快照比对,检测新消息并推送事件。
|
||||
- **AI 话术回复**:人设描述驱动 AI 自由发挥 + 固定模板兜底(关键词命中优先),调用 OpenAI 兼容接口(base-url/api-key/model 可配)。
|
||||
- **回复模式**:默认半自动(PC 端预览 AI 回复,点击"发送"才在手机输入发送),提供全自动开关。
|
||||
- **监控与日志**:消息事件、AI 生成内容、发送结果完整记录,支持手动重发。
|
||||
|
||||
## 交互界面
|
||||
|
||||
JavaFX 桌面窗口,深色科技风,顶部工具栏 + 中央分栏布局:左侧聊天记录预览,右侧配置面板(联系人/话术与AI/监控日志三个页签),设备、微信、监控、AI 四色状态徽标实时反馈。
|
||||
|
||||
## 技术栈
|
||||
|
||||
- Java 17 + Spring Boot 2.7.18 + JavaFX 17(沿用现有桌面架构)
|
||||
- ADB:直接调用 `adb` 命令行(`devices` / `shell am start` / `shell uiautomator dump` / `shell screencap` / `shell input tap|text|swipe` / `shell dumpsys window`)
|
||||
- AI 调用:JDK17 自带 `java.net.http.HttpClient` 调 OpenAI 兼容 `chat/completions`,**不新增 Maven 依赖**(pom 不动)
|
||||
- 配置持久化:`data/wechat-ai/config.json`(fastjson 读写,沿用项目现有 JSON 序列化方式)
|
||||
- 日志:SLF4J + logback(项目现有),UI 日志区双写
|
||||
|
||||
## 实现方式
|
||||
|
||||
**策略**:删除旧插件后,以"纯 Java ADB 直连 + 文本 dump 优先 + 视觉兜底"的方式重建。微信聊天界面是原生控件,`uiautomator dump` 可直接拿到消息文本与发送者,比截图识图更精确、零成本;截图仅在新消息检测/图片消息/解析失败兜底时触发,配合多模态模型识别。
|
||||
|
||||
**关键决策**:
|
||||
|
||||
- dump 优先而非全量识图:uiautomator XML 直接含 text/content-desc 属性,解析效率高、无 OCR 误差;视觉模型仅在兜底路径启用。
|
||||
- 轮询快照比对:Monitor 记录每个指定会话的最新消息 hash,仅在新 hash 出现时才触发 AI,避免重复回复。
|
||||
- 半自动默认 + 全自动开关:AI 生成结果先回传 UI 预览,防止误发;开关一键切换。
|
||||
- 话术两级:固定模板(关键词→固定回复,命中直接采用)优先于 AI 生成,保证确定性场景可控。
|
||||
- 所有 AI/ADB 参数在 UI 可配并持久化,模型/密钥不硬编码。
|
||||
|
||||
**性能与可靠性**:
|
||||
|
||||
- 轮询默认间隔 3~5 秒(可配),单次 dump 约 1~2 秒,解析仅取文本节点 O(n),无性能瓶颈;截图仅在必要时触发。
|
||||
- AI 请求设置 30s 超时 + 单次重试,失败不阻塞监控线程,事件落入日志。
|
||||
- 边界处理:设备断开、未授权、微信未安装/未登录、dump 失败(回退截图+视觉)、消息为空/超长(截断)。
|
||||
|
||||
**日志**:AI 请求记录到 UI 日志区(截断至 200 字,不打印 api-key);错误可操作性强、不 dump 大对象。
|
||||
|
||||
**爆炸半径控制**:删除前全仓复核 `mobile-ui-auto`/`mobileuiauto` 引用(已定位 MainWindow 图标映射、plugins.config 模板、插件配置测试);新插件 ID 独立,不影响其他插件;data 目录占用删除失败时提示手动清理、不阻塞编译。
|
||||
|
||||
## 架构设计
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
UI[WechatAiWindow JavaFX] --> SVC[WechatAiService]
|
||||
SVC --> ADB[AdbClient]
|
||||
SVC --> MON[MessageMonitor]
|
||||
SVC --> AI[AiResponder]
|
||||
ADB --> PHONE[安卓手机微信]
|
||||
MON --> READER[WechatSessionReader]
|
||||
READER --> ADB
|
||||
AI --> HTTP[OpenAI兼容API]
|
||||
SVC --> CFG[config.json 持久化]
|
||||
UI --> EVT[事件回调: 设备状态/新消息/AI结果/日志]
|
||||
EVT --> UI
|
||||
```
|
||||
|
||||
**模块划分**:
|
||||
|
||||
- `adb` 层:AdbClient(命令封装)、AdbDevice(设备模型)——独立于微信逻辑,可复用。
|
||||
- `wechat` 层:WechatSessionReader(dump 解析/滚动/截图)、WechatMessage/WechatSession(模型)、MessageMonitor(轮询监测,事件回调)。
|
||||
- `ai` 层:AiResponder(消息组装/模板命中/HTTP 调用/超时重试)、AiConfig(模型参数)。
|
||||
- `ui` 层:WechatAiWindow(四页签)、WechatAiPlugin(插件注册与生命周期)。
|
||||
|
||||
**数据流**:Monitor 轮询 → Reader dump 会话页 → 解析文本节点 → 快照比对发现新消息 → 回调 UI(消息+截图)→ AiResponder 组装(system 人设 + 历史 + 模板)→ 生成回复 → 半自动预览/全自动直发 → AdbClient input 输入发送 → 日志记录。
|
||||
|
||||
## 目录结构
|
||||
|
||||
### 删除(方案C)
|
||||
|
||||
```
|
||||
src/main/java/com/example/homeutils/biz/mobileuiauto/ # [DELETE] 整个包(Plugin/Window/Service/7个model,共10个文件)
|
||||
src/main/resources/mobile-ui-auto/ # [DELETE] 整个目录(python/runner.py、requirements.txt、install_tools.py、templates)
|
||||
data/mobile-ui-auto/ # [DELETE] 运行数据(含 .venv,占用时提示手动清理)
|
||||
```
|
||||
|
||||
### 修改
|
||||
|
||||
```
|
||||
src/main/resources/templates/plugins.config # [MODIFY] plugins.order=mobile-ui-auto → wechat-ai
|
||||
src/main/java/com/example/homeutils/system/ui/MainWindow.java # [MODIFY] 第325行 AppIcon switch 的 "mobile-ui-auto" case 替换为新ID(先复核该switch)
|
||||
src/test/java/com/example/homeutils/system/plugin/DefaultPluginConfigurationTest.java # [MODIFY] 测试配置模板中 mobile-ui-auto 引用更新为新ID
|
||||
```
|
||||
|
||||
### 新建
|
||||
|
||||
```
|
||||
src/main/java/com/example/homeutils/biz/wechatai/
|
||||
├── WechatAiPlugin.java # [NEW] 插件注册:id=wechat-ai,name=微信AI助手,commandName=wechat-ai,实现 Plugin 生命周期与 VisualPluginFactory
|
||||
├── WechatAiWindow.java # [NEW] JavaFX 主窗口:顶部工具栏(设备/启动微信/监控主开关+模式切换)、中央分栏(左侧聊天记录预览+截图,右侧 TabPane: 联系人/话术与AI/监控日志);沿用 Theme/StyledButton
|
||||
├── WechatAiService.java # [NEW] 编排服务:组装 AdbClient/Reader/Monitor/AiResponder,提供 start/stop/发送/配置读写,事件分发到 UI
|
||||
├── adb/
|
||||
│ ├── AdbClient.java # [NEW] adb 命令封装:listDevices/connect/tap/input/screenshot/dumpUiXml/foregroundPackage/startApp;解析 dump XML 文本节点
|
||||
│ └── AdbDevice.java # [NEW] 设备模型(serial/state/model),含无线连接地址解析
|
||||
├── wechat/
|
||||
│ ├── WechatSessionReader.java # [NEW] 打开微信(com.tencent.mm)→dump会话列表/聊天页→解析消息(发送者/内容/时间)→滚动加载→截图
|
||||
│ ├── WechatMessage.java # [NEW] 消息模型(sender/content/time/type)
|
||||
│ ├── WechatSession.java # [NEW] 会话模型(title/messages/lastHash)
|
||||
│ └── MessageMonitor.java # [NEW] 定时轮询线程:快照比对检测指定联系人的新消息,回调事件;支持启动/停止/间隔配置
|
||||
├── ai/
|
||||
│ ├── AiResponder.java # [NEW] HttpClient 调 chat/completions;system=人设+话术;固定模板命中优先;超时30s+重试1次;可选 base64 视觉消息
|
||||
│ └── AiConfig.java # [NEW] 模型配置模型(baseUrl/apiKey/model/温度/超时)
|
||||
└── config/
|
||||
└── WechatAiProperties.java # [NEW] data/wechat-ai/config.json 读写:联系人名单/话术模板/AI配置/监控间隔/模式开关
|
||||
```
|
||||
|
||||
## 关键代码结构
|
||||
|
||||
```java
|
||||
// AdbClient 核心接口(adb 命令封装,全部通过 ProcessBuilder 执行)
|
||||
public class AdbClient {
|
||||
List<AdbDevice> listDevices() throws IOException;
|
||||
String foregroundPackage(String serial) throws IOException;
|
||||
void startApp(String serial, String packageName) throws IOException;
|
||||
Path screenshot(String serial, Path outPng) throws IOException;
|
||||
List<UiNode> dumpUiXml(String serial) throws IOException; // uiautomator dump + XML 解析
|
||||
void tap(String serial, int x, int y) throws IOException;
|
||||
void inputText(String serial, String text) throws IOException; // 中文经 ADBKeyboard 或剪贴板方式处理
|
||||
void swipe(String serial, int x1, int y1, int x2, int y2, int ms) throws IOException;
|
||||
}
|
||||
|
||||
// MessageMonitor 事件回调(解耦监测与 UI/AI)
|
||||
public interface MessageMonitorListener {
|
||||
void onNewMessage(WechatSession session, WechatMessage msg, Path screenshot);
|
||||
void onMonitorError(String message);
|
||||
void onStatusChanged(boolean running);
|
||||
}
|
||||
```
|
||||
|
||||
## 设计风格
|
||||
|
||||
深色现代科技风桌面应用,与 homeutils 现有 Theme(BG_BODY 深色系、StyledButton、AtlantaFX)体系保持一致。顶部工具栏承载核心操作(设备连接、启动微信、监控主开关、自动/手动模式切换),配四色状态徽标(设备/微信/监控/AI)。中央采用分栏布局:左侧聊天记录列表 + 消息详情/手机截图预览,右侧设置面板以 TabPane 组织(指定联系人、话术与 AI、监控日志)。卡片化面板、圆角、克制的悬停反馈与状态色点缀,信息层级清晰,长时间监控不刺眼。
|
||||
|
||||
## Agent Extensions
|
||||
|
||||
### MCP
|
||||
|
||||
- **Windows CLI MCP Server**
|
||||
- Purpose: 执行删除操作(`cmd /c rmdir /s /q` 删除旧插件代码/资源/data 目录,规避 Windows 文件占用拦截)、编译验证(`mvnw.cmd compile -q`)、启动应用并检查 data/plugins.config 与侧边栏插件加载结果
|
||||
- Expected outcome: 旧插件相关文件与 Python 环境被彻底清理,新插件编译通过、应用启动后"微信AI助手"出现在侧边栏且原"手机UI自动化"消失
|
||||
|
||||
### SubAgent
|
||||
|
||||
- **code-explorer**
|
||||
- Purpose: 在删除前全仓复核 `mobile-ui-auto`/`mobileuiauto`/`MobileUiAutomation` 的所有引用点(MainWindow 图标 switch、配置、测试、文档),确认无遗漏后才执行删除
|
||||
- Expected outcome: 输出完整引用清单,确保删除后编译无残留错误、无死引用
|
||||
@@ -0,0 +1,228 @@
|
||||
---
|
||||
name: 系统设置重构-直接打开配置文件
|
||||
overview: 重构系统设置窗口,去掉繁琐的表单填写,改为每个 Tab 直接打开 data 目录下对应配置文件,用系统默认编辑器快速配置,每个 Tab 只管理自己栏目的配置。
|
||||
design:
|
||||
styleKeywords:
|
||||
- Clean
|
||||
- Minimalist
|
||||
fontSystem:
|
||||
fontFamily: Microsoft YaHei
|
||||
heading:
|
||||
size: 16px
|
||||
weight: 700
|
||||
subheading:
|
||||
size: 14px
|
||||
weight: 600
|
||||
body:
|
||||
size: 13px
|
||||
weight: 400
|
||||
colorSystem:
|
||||
primary:
|
||||
- "#4CAF50"
|
||||
background:
|
||||
- "#F5F5F5"
|
||||
- "#FFFFFF"
|
||||
text:
|
||||
- "#333333"
|
||||
- "#666666"
|
||||
functional:
|
||||
- "#FF9800"
|
||||
- "#F44336"
|
||||
todos:
|
||||
- id: refactor-external-config
|
||||
content: 移除 ExternalConfigManager 中 MyBatis 相关配置节,只保留系统路径、数据文件路径和字体大小
|
||||
status: completed
|
||||
- id: refactor-path-tab
|
||||
content: 重构系统路径 Tab,移除表单,改为显示 workutils.config 路径 + 打开按钮 + 重新加载按钮
|
||||
status: completed
|
||||
dependencies:
|
||||
- refactor-external-config
|
||||
- id: refactor-mybatis-tab
|
||||
content: 重构 MyBatis 数据库 Tab,移除表单,改为显示 mybatis-generator.properties 路径 + 打开按钮 + 重新加载按钮
|
||||
status: completed
|
||||
dependencies:
|
||||
- refactor-external-config
|
||||
- id: refactor-project-tab
|
||||
content: 重构项目路径 Tab,移除 TextArea,改为显示 project_paths.txt 路径 + 打开按钮,保留批量替换工具
|
||||
status: completed
|
||||
- id: add-datasource-tab
|
||||
content: 新增多数据源 Tab,显示 datasources.json 路径 + 打开按钮 + 重新加载按钮
|
||||
status: completed
|
||||
- id: refactor-damaged-cache-tab
|
||||
content: 重构损坏缓存 Tab,移除 TextArea,改为显示 damaged_repos.cache 路径 + 打开按钮 + 清理缓存按钮
|
||||
status: completed
|
||||
- id: add-open-file-util
|
||||
content: 新增 openFileInEditor 工具方法,支持 Desktop.edit 和 notepad fallback
|
||||
status: completed
|
||||
- id: compile-test
|
||||
content: 编译验证并测试所有 Tab 功能
|
||||
status: completed
|
||||
dependencies:
|
||||
- refactor-path-tab
|
||||
- refactor-mybatis-tab
|
||||
- refactor-project-tab
|
||||
- add-datasource-tab
|
||||
- refactor-damaged-cache-tab
|
||||
- add-open-file-util
|
||||
---
|
||||
|
||||
## 产品概述
|
||||
|
||||
重构系统设置窗口,去掉繁琐的 JavaFX 表单填写体验,改为每个 Tab 直接打开 data 目录下对应的配置文件,用系统默认编辑器(记事本/IDE)快速配置。每个 Tab 只管理自己栏目的配置,各配置文件独立管理。
|
||||
|
||||
## 核心功能
|
||||
|
||||
- **系统路径 Tab**:显示 `data/workutils.config` 文件路径,提供「用记事本打开」按钮直接编辑系统路径和字体设置
|
||||
- **MyBatis 数据库 Tab**:显示 `data/mybatis-generator.properties` 文件路径,提供「用记事本打开」按钮直接编辑数据库连接和包路径配置
|
||||
- **项目路径 Tab**:显示 `data/project_paths.txt` 文件路径,提供「用记事本打开」按钮直接编辑项目路径列表
|
||||
- **多数据源 Tab**:显示 `data/datasources.json` 文件路径,提供「用记事本打开」按钮直接编辑多数据源配置
|
||||
- **损坏缓存 Tab**:显示 `data/damaged_repos.cache` 文件路径,标记为只读,提供「用记事本打开」按钮查看,保留「清理缓存」按钮
|
||||
- **重新加载**:每个 Tab 提供「重新加载」按钮,让程序重新读取文件使配置生效
|
||||
- **ExternalConfigManager 精简**:移除 `SECTIONS` 中的 MyBatis 相关配置节,只保留系统路径、数据文件路径和字体大小
|
||||
|
||||
## 技术栈
|
||||
|
||||
- JavaFX(原有技术栈,保持一致的 UI 风格)
|
||||
- Desktop.getDesktop().edit() 打开配置文件(Windows 下用默认编辑器打开)
|
||||
|
||||
## 实施方案
|
||||
|
||||
### 架构设计
|
||||
|
||||
重构后的设置窗口每个 Tab 统一结构:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Tab 标题(如:系统路径) │
|
||||
│ │
|
||||
│ 配置文件: C:\xxx\data\workutils.config │
|
||||
│ │
|
||||
│ [用记事本打开] [重新加载] │
|
||||
│ │
|
||||
│ 说明文字:编辑后点击「重新加载」生效,无需重启。 │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 关键修改点
|
||||
|
||||
#### 1. SettingsWindow.java — 重构各 Tab
|
||||
|
||||
**createPathTab()**(系统路径 Tab):
|
||||
|
||||
- 移除所有 GridPane 表单行(tfBaseDir、tfExportDir 等 TextField)
|
||||
- 显示 `properties.getWorkutilsConfigFilePath()` 绝对路径
|
||||
- 保留「用记事本打开」按钮(调用 `Desktop.getDesktop().edit(file)`)
|
||||
- 保留「重新加载」按钮(调用 `properties.mergeExternal(configManager.load())`)
|
||||
- 保留字体大小设置说明(字体设置仍在 workutils.config 中)
|
||||
|
||||
**createMyBatisTab()**(MyBatis 数据库 Tab):
|
||||
|
||||
- 完全移除 GridPane 表单(tfDbDriver、tfDbUrl 等)
|
||||
- 显示 `properties.getMybatisGeneratorFilePath()` 绝对路径
|
||||
- 「用记事本打开」按钮打开 `data/mybatis-generator.properties`
|
||||
- 「重新加载」按钮调用已有逻辑重新加载 MyBatis 配置
|
||||
- 移除「从内置配置加载」按钮(用户直接编辑文件即可)
|
||||
|
||||
**createProjectTab()**(项目路径 Tab):
|
||||
|
||||
- 移除 TextArea + 加载/保存按钮的复杂结构
|
||||
- 显示 `properties.getProjectPathsFilePath()` 绝对路径
|
||||
- 「用记事本打开」按钮打开 `data/project_paths.txt`
|
||||
- 保留「重新加载」按钮刷新项目路径列表
|
||||
- **保留批量替换工具**(这是用户之前明确需求的功能,在 memory ID 70362697 中有记录)
|
||||
|
||||
**createDatasourceTab()**(新增 Tab — 多数据源):
|
||||
|
||||
- 显示 `properties.getDatasourcesFilePath()` 绝对路径
|
||||
- 「用记事本打开」按钮打开 `data/datasources.json`
|
||||
- 「重新加载」按钮调用 `datasourceConfigManager.reload()`
|
||||
|
||||
**createDamagedCacheTab()**(损坏缓存 Tab,替代原项目管理 Tab 中的子 Tab):
|
||||
|
||||
- 显示 `properties.getDamagedReposFilePath()` 绝对路径
|
||||
- 标记为只读(加提示文字)
|
||||
- 「用记事本打开」按钮打开 `data/damaged_repos.cache`
|
||||
- 保留「清理缓存」按钮
|
||||
|
||||
**createDisplayTab()**(显示设置 Tab):
|
||||
|
||||
- 字体设置仍在 `workutils.config` 中,所以此 Tab 内容与系统路径 Tab 操作的是同一个文件
|
||||
- 可以简化为一个提示:「字体设置请在 workutils.config 中修改 font.size.* 属性」+ 「重新加载」按钮
|
||||
- 或者保留现有的滑块预览(用户可能喜欢实时预览字体效果),但保存时改为提示用户去文件编辑
|
||||
|
||||
**建议**:显示设置 Tab 保留现有滑块预览功能(用户体验好),但「保存」按钮改为提示用户手动编辑 workutils.config,或仍通过 `ExternalConfigManager.saveSectioned()` 保存字体设置(因为字体设置是系统级的,适合集中管理)。
|
||||
|
||||
#### 2. ExternalConfigManager.java — 移除 MyBatis 配置节
|
||||
|
||||
修改 `SECTIONS` 静态初始化块,移除:
|
||||
|
||||
- `"===== MyBatis 数据库连接(覆盖内置 mybatis-generator.properties)====="`
|
||||
- `"===== MyBatis 代码生成包路径 ====="`
|
||||
|
||||
只保留:
|
||||
|
||||
- `"===== 系统路径 ====="`
|
||||
- `"===== 数据文件路径 ====="`
|
||||
- `"===== 字体大小(显示设置) ====="`
|
||||
|
||||
同步移除对应的 KEY 常量(或修改注释说明这些 KEY 仅用于 workutils.config)。
|
||||
|
||||
#### 3. 打开文件工具方法
|
||||
|
||||
在 SettingsWindow 中新增工具方法:
|
||||
|
||||
```java
|
||||
private void openFileInEditor(Path file) {
|
||||
try {
|
||||
if (!Files.exists(file)) {
|
||||
Files.createDirectories(file.getParent());
|
||||
Files.createFile(file);
|
||||
}
|
||||
// Windows: Desktop.edit 用关联程序打开并允许编辑
|
||||
// 如果 Desktop 不可用,fallback 到 Runtime.exec("notepad")
|
||||
if (Desktop.isDesktopSupported()) {
|
||||
Desktop.getDesktop().edit(file.toFile());
|
||||
} else {
|
||||
// Windows fallback
|
||||
Runtime.getRuntime().exec(new String[]{"notepad", file.toAbsolutePath().toString()});
|
||||
}
|
||||
} catch (Exception e) {
|
||||
showAlert(AlertType.ERROR, "打开文件失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 实施注意事项
|
||||
|
||||
1. **Desktop.getDesktop().edit()** 在 Windows 上需要文件有关联的编辑器,且文件必须存在
|
||||
2. **批量替换工具保留**:用户的 memory 中明确提到需要保留项目路径批量替换功能,不能删除
|
||||
3. **向后兼容**:workutils.config 中如果仍有旧的 MyBatis 配置项,程序应能忽略(不报错)
|
||||
4. **文件不存在处理**:打开前检查文件是否存在,不存在则创建空文件或从模板复制
|
||||
|
||||
### 目录结构变更
|
||||
|
||||
```
|
||||
src/main/java/com/example/workutils/system/config/
|
||||
├── SettingsWindow.java [MODIFY] 重构所有 Tab 内容
|
||||
├── ExternalConfigManager.java [MODIFY] 移除 MyBatis 配置节
|
||||
├── WorkUtilsProperties.java [NO CHANGE] 无需修改
|
||||
├── DatasourceConfigManager.java [NO CHANGE] 无需修改
|
||||
└── ConfigInitializer.java [NO CHANGE] 无需修改
|
||||
```
|
||||
|
||||
无需新增文件,只需修改现有两个文件。
|
||||
|
||||
## 设计风格
|
||||
|
||||
保持现有 JavaFX 窗口的简洁风格,每个 Tab 内容统一为:
|
||||
|
||||
- 顶部:标题(加粗,字号稍大)
|
||||
- 中部:配置文件路径(等宽字体,可选择性可复制)
|
||||
- 按钮区:[]用记事本打开] []重新加载](对齐,间距合理)
|
||||
- 底部:说明文字(灰色,小字号)
|
||||
|
||||
## 布局说明
|
||||
|
||||
每个 Tab 使用 VBox 垂直布局,内容居中偏左对齐,整体留白适中(Insets 12px)。
|
||||
按钮使用 HBox 水平排列,间距 10px。
|
||||
路径 Label 使用等宽字体(Consolas),背景浅灰,增加可读性。
|
||||
@@ -0,0 +1,36 @@
|
||||
# WorkUtils UI 开发规则
|
||||
|
||||
## 1. CSS 优先级铁律(AtlantaFX 环境)
|
||||
|
||||
### 文本颜色
|
||||
- **禁止**纯 CSS 设置导航栏选中文字色,AtlantaFX `.label` 会覆盖(含 `!important`)。
|
||||
- **正确做法**:Java 代码中 `label.setTextFill(Color.WHITE)` 直接设置。
|
||||
|
||||
### 背景透明
|
||||
- ListView 内部容器透明需覆盖完整链路:`.list-view`, `.viewport`, `.virtual-flow`, `.virtual-flow > *`, `.clipped-container`, `.sheet`, `.corner`。
|
||||
- 同时用 Java 代码 `setStyle("-fx-background-color: transparent;")` 做 inline 兜底。
|
||||
|
||||
### 选中态
|
||||
- **必须同时覆盖** `.list-cell:selected` 和 `.list-cell:filled:selected`。
|
||||
- `.list-cell:selected` 设置透明背景兜底 → 防止虚拟化复用时空 cell 闪现蓝色。
|
||||
- `.list-cell:filled:selected` 设置激活背景 → CSS 优先级更高,非空选中 cell 生效。
|
||||
|
||||
## 2. ListView 虚拟化陷阱
|
||||
|
||||
- ListView 使用 VirtualFlow,cell 会被复用。每次 `updateItem(empty=true)` 时:
|
||||
- 必须清理自定义 style class(先 removeAll 再按需 add)。
|
||||
- 禁止 empty 分支中直接用 `setAll()`(会误删 JavaFX 内置 `list-cell` class)。
|
||||
- `selectedProperty()` listener 中调用 `updateStyleClass()` 时,要兼容 empty 状态。
|
||||
|
||||
## 3. 布局规则
|
||||
|
||||
- ListView 导航栏使用 `VBox.setVgrow(navList, Priority.ALWAYS)` 撑满剩余空间。
|
||||
- **不要**在 `refreshNavItems()` 中重新设置 prefHeight/minHeight/maxHeight,会与 grow 冲突。
|
||||
- 滚动条自然出现在 ListView 右侧底部,无需额外处理。
|
||||
|
||||
## 4. 修改验证流程
|
||||
|
||||
修改 UI 样式后:
|
||||
1. 先检查 AtlantaFX/modena.css 是否有同名规则覆盖。
|
||||
2. 优先使用 Java 端代码设置(`setStyle`/`setTextFill`),再补充 CSS。
|
||||
3. 对虚拟化组件(ListView/TableView),验证 resize 窗口场景。
|
||||
@@ -0,0 +1,133 @@
|
||||
# WorkUtils 项目规则
|
||||
# https://www.codebuddy.ai/docs/zh/IDE/User-guide/Workspace
|
||||
version: 1
|
||||
|
||||
# ===== 项目信息 =====
|
||||
name: workutils
|
||||
description: WorkUtils API 文档生成工具
|
||||
|
||||
# ===== 规则定义 =====
|
||||
rules:
|
||||
|
||||
# 1. 导出目录 —— 禁止全文搜索
|
||||
- id: no-export-search
|
||||
description: |
|
||||
禁止对 export/ 目录进行搜索/读取操作。
|
||||
该目录包含导出的 HTML 文件,单文件可达数 MB,ripgrep 默认跳过超长行导致结果不准确。
|
||||
condition: "path starts with 'export/'"
|
||||
action: "reject"
|
||||
fallback: "如需调试导出结果,使用源码模板文件 (templates/apidoc/*.js) + 单元测试验证"
|
||||
|
||||
# 2. 模板规范 —— 禁止 code-in-string 反模式
|
||||
- id: no-code-in-string
|
||||
description: |
|
||||
禁止在 JS 中用函数返回压缩字符串来重复已有代码。
|
||||
典型反模式:SNAPSHOT_JS() { return 'function sendDubboRequest(){...}' }
|
||||
这种方式导致:
|
||||
- 三层转义地狱 (JS字符串→HTML→JS参数)
|
||||
- 无法调试、无法 lint、无法语法高亮
|
||||
- 代码漂移:修改 api-doc.js 后快照版不会同步
|
||||
正确方式:window.__API_DOC_JS__ = {{JS_JSON}}; // 复用原文
|
||||
example: |
|
||||
# 错误示例
|
||||
function SNAPSHOT_JS() {
|
||||
return 'function sendDubboRequest(){var e=buildDubboBody();...}';
|
||||
}
|
||||
# 正确示例
|
||||
var mainJs = window.__API_DOC_JS__; // 由 Java 注入的 JSON
|
||||
var override = 'function getActiveDubboCard(){...}';
|
||||
var fullJs = override + '\n' + mainJs;
|
||||
enforcement: "warn"
|
||||
severity: high
|
||||
|
||||
# 3. 占位符命名规范
|
||||
- id: placeholder-naming
|
||||
description: "模板占位符统一使用 {{NAME}} 格式,双大写加下划线"
|
||||
pattern: "\\{\\{[A-Z][A-Z0-9_]*\\}\\}"
|
||||
enforcement: "review"
|
||||
|
||||
# 4. 大文件读取检查
|
||||
- id: large-file-check
|
||||
description: |
|
||||
读取 >500KB 文件前先检查行数和内容分布。
|
||||
超大文件(如压缩后的 JS/CSS、生成的 HTML)不适合直接读取全文。
|
||||
condition: "file.size > 500KB"
|
||||
action: "warn"
|
||||
suggestion: "使用 head/tail 检查文件结构,或使用单元测试验证行为"
|
||||
|
||||
# 5. 转义函数集中管理
|
||||
- id: escape-centralized
|
||||
description: |
|
||||
HTML/JS/JSON 转义函数统一在 Java 侧或独立工具模块管理。
|
||||
避免在 JS 源码中混用多种转义方式(\\、\\\、\\'、' 等)。
|
||||
files: ["ApiDocGenerator.java"]
|
||||
enforcement: "review"
|
||||
|
||||
# 6. Git 忽略大型产物
|
||||
- id: gitignore-export
|
||||
description: "export/ 目录应加入 .gitignore,避免提交大型产物文件"
|
||||
action: "suggest"
|
||||
suggestion: "echo 'export/' >> .gitignore"
|
||||
|
||||
# 7. 复杂重构分步提交 —— 避免会话中断丢失工作
|
||||
- id: refactor-step-by-step
|
||||
description: |
|
||||
涉及 ≥4 个文件 或 ≥200 行变更 的复杂重构,必须分多个 commit 完成,避免单次会话中断丢失全部工作。
|
||||
典型场景:
|
||||
- 字段/类重命名(如 navButtons → navList)会触发多文件交叉引用更新
|
||||
- 组件替换(Button → ListView)涉及字段、方法、引用、样式、测试多文件
|
||||
- 框架/库升级涉及配置文件、依赖、调用点、文档
|
||||
推荐步骤:
|
||||
① 第一步:加新常量/CSS/配置项(与旧实现共存)
|
||||
② 第二步:替换实现/切换调用点
|
||||
③ 第三步:删除旧代码(清理 commit)
|
||||
每步完成后提交,便于回滚。
|
||||
condition: "涉及文件数 >= 4 OR 变更行数 >= 200"
|
||||
action: "warn"
|
||||
severity: high
|
||||
|
||||
# 8. AtlantaFX UI 防中断规则 —— 修改 MainWindow/Theme/CSS 时必读
|
||||
- id: atlantafx-ui-pitfalls
|
||||
description: |
|
||||
修改 MainWindow.java、Theme.java 或 light-theme.css 时,必须遵守以下规则,避免反复修改同一问题导致会话中断:
|
||||
|
||||
【CSS 优先级】
|
||||
- AtlantaFX 的 .label 规则优先级极高,!important 也会被覆盖
|
||||
- 导航栏选中文字色:必须用 Java 代码 label.setTextFill(Color.WHITE),不能靠 CSS
|
||||
- ListView 选中态:必须同时覆盖 .list-cell:selected(为空 cell 兜底)和 .list-cell:filled:selected(为非空 cell 设置激活背景)
|
||||
- 背景透明:需要完整覆盖 .list-view → .virtual-flow → .clipped-container → .sheet 全链路
|
||||
|
||||
【ListView 虚拟化】
|
||||
- cell 会被 VirtualFlow 复用,updateItem(empty=true) 时必须清理自定义 style class
|
||||
- 不要用 getStyleClass().setAll(),会误删 JavaFX 内置 list-cell class;用 removeAll + add
|
||||
- 窗口 resize 时 cell 复用会暴露 empty cell 被 selected 的问题
|
||||
|
||||
【布局】
|
||||
- 导航 ListView 用 VBox.setVgrow(ALWAYS) 撑满
|
||||
- refreshNavItems() 中不要重新设置 prefHeight/minHeight/maxHeight
|
||||
|
||||
【修改后自检清单】
|
||||
① 小窗口(菜单项少)→ 无滚动条,无底部蓝块
|
||||
② 选中菜单 → 文字白色,背景蓝色,左侧蓝条可见
|
||||
③ 最大化窗口 → 无额外蓝色块闪现,滚动条在导航栏底部
|
||||
files: ["MainWindow.java", "Theme.java", "light-theme.css"]
|
||||
action: "warn"
|
||||
severity: high
|
||||
|
||||
# ===== 触发提示 =====
|
||||
# 当规则被触发时,AI 会看到这些提示
|
||||
messages:
|
||||
no-export-search: |
|
||||
⚠️ 检测到对 export/ 目录的操作。
|
||||
该目录包含导出的 HTML 文件(单文件可达数 MB),不适合搜索/读取。
|
||||
请改用源码模板文件 (src/main/resources/templates/apidoc/*.js) 进行调试。
|
||||
large-file-check: |
|
||||
⚠️ 目标文件 >500KB,可能是压缩产物或大型导出文件。
|
||||
建议使用 head/tail 检查结构,或通过单元测试验证行为。
|
||||
refactor-step-by-step: |
|
||||
⚠️ 检测到复杂重构(≥4 文件 或 ≥200 行)。
|
||||
建议分步提交:
|
||||
① 第一步:加新常量/CSS(与旧实现共存)
|
||||
② 第二步:替换实现/切换调用点
|
||||
③ 第三步:删除旧代码
|
||||
每步完成后 git commit,避免会话中断丢失工作。
|
||||
Reference in New Issue
Block a user