diff --git a/.superpowers/sdd/.gitignore b/.superpowers/sdd/.gitignore deleted file mode 100644 index d6b7ef3..0000000 --- a/.superpowers/sdd/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore diff --git a/docs/audit/plugin-ui-code-audit.md b/docs/audit/plugin-ui-code-audit.md new file mode 100644 index 0000000..a65f5e5 --- /dev/null +++ b/docs/audit/plugin-ui-code-audit.md @@ -0,0 +1,432 @@ +# WorkUtils æ�’ä»¶ UI 与代ç �å�¯ç»´æŠ¤æ€§å®¡æŸ¥ + +审查日期:2026-07-30 + +## 1. 结论 + +当å‰�产å“�å·²ç»�å½¢æˆ�统一的左侧导航ã€�颜色和基础按钮风格,但å�„æ�’ä»¶ä»�是“æ¯�个 Window 自己æ�­ UIã€�自己开线程ã€�自己管ç�† loadingã€�自己处ç�†é”™è¯¯â€�的实现方å¼�。视觉统一å�œç•™åœ¨é¢œè‰²å±‚,交互状æ€�和代ç �结构没有统一。 + +主è¦�风险: + +1. `Window` 类过大:8 个窗å�£å¹³å�‡çº¦ 824 行,`MobileUiAutomationWindow` è¾¾ 1702 行。 +2. 异步状æ€�没有统一模型:存在 `new Thread`ã€�`Task`ã€�`CompletableFuture`ã€�布尔字段和手动 `Platform.runLater` 等多套实现。 +3. loading 行为ä¸�一致:有的å�ªç¦�用按钮,有的改文字,有的显示旋转图标,有的å�Œæ—¶æ˜¾ç¤ºå�œæ­¢æŒ‰é’®ï¼›å¼‚常分支容易æ¼�æ�¢å¤�状æ€�。 +4. UI 直接暴露æ•�感é…�置:Git 远程 URL 显示账å�·ï¼Œæ•°æ�®åº“生æˆ�器显示完整 JDBC URL 和用户å��。 +5. æ“�作层级ä¸�清:刷新ã€�执行ã€�交æ�¢ã€�终止ã€�删除等按钮ç»�常处于å�Œä¸€è§†è§‰å±‚级。 +6. 空状æ€�æ™®é��å�ªæ˜¯å¤§ç‰‡ç©ºç™½ï¼Œç”¨æˆ·æ— æ³•判断是“尚未执行â€�“没有数æ�®â€�还是“执行失败â€�。 +7. UIã€�业务编排ã€�文件æ“�作ã€�历å�²è®°å½•和线程控制混在å�Œä¸€ä¸ªç±»é‡Œï¼ŒAI 修改局部功能时需è¦�ç�†è§£æ•´ä¸ªçª—å�£ï¼Œè¯¯æ”¹æ¦‚率高。 + +建议先建设公共 UI/异步基础设施,å†�é€�æ�’ä»¶è¿�移。ä¸�è¦�å�Œæ—¶é‡�写所有æ�’件。 + +## 2. 统一设计与代ç �基线 + +### 2.1 页é�¢ç»“æž„ + +所有æ�’件统一为: + +1. `PageHeader`:标题ã€�简短说明ã€�帮助入å�£ã€‚ +2. `ConfigCard`:输入与选项。 +3. `ActionBar`:一个主æ“�作ã€�零到两个次æ“�作ã€�一个æ�¡ä»¶æ˜¾ç¤ºçš„å�–消æ“�作。 +4. `OperationStatus`:阶段ã€�进度ã€�耗时ã€�当å‰�处ç�†å¯¹è±¡ã€‚ +5. `ResultArea`:结果ã€�空状æ€�ã€�失败状æ€�。 +6. `HistoryTable`:历å�²è®°å½•放在独立 Tab 或折å� åŒºï¼Œä¸�抢å� ä¸»ä»»åŠ¡ç©ºé—´ã€‚ + +### 2.2 按钮状æ€� + +按钮ä¸�应由业务代ç �直接å��å¤�调用 `setText`ã€�`setDisable`ã€�`setGraphic`。统一使用状æ€�: + +```java +public enum OperationState { + IDLE, VALIDATING, RUNNING, CANCELLING, SUCCEEDED, FAILED +} +``` + +统一按钮规范: + +| 状æ€� | 主按钮 | å�–消按钮 | 输入区 | +|---|---|---|---| +| IDLE | å�¯ç”¨ï¼Œæ˜¾ç¤ºåŠ¨ä½œå��ç§° | éš�è—� | å�¯ç¼–辑 | +| VALIDATING | spinner +“校验中â€� | éš�è—� | ç¦�用 | +| RUNNING | spinner + 阶段å��ç§° | 显示 | ç¦�用 | +| CANCELLING | “正在å�œæ­¢â€¦â€� | ç¦�用 | ç¦�用 | +| SUCCEEDED | æ�¢å¤�动作å��ç§° | éš�è—� | å�¯ç¼–辑 | +| FAILED | æ�¢å¤�动作å��ç§° | éš�è—� | å�¯ç¼–辑 | + +建议增加公共组件: + +```java +public final class AsyncAction { + private final ReadOnlyObjectWrapper state = + new ReadOnlyObjectWrapper<>(OperationState.IDLE); + private final StringProperty message = new SimpleStringProperty(""); + private final DoubleProperty progress = new SimpleDoubleProperty(-1); + + public void run( + Supplier work, + Consumer onSuccess, + Consumer onFailure) { + if (state.get() == OperationState.RUNNING) return; + state.set(OperationState.RUNNING); + + Task task = new Task<>() { + @Override protected T call() { return work.get(); } + }; + task.setOnSucceeded(e -> finish(() -> onSuccess.accept(task.getValue()))); + task.setOnFailed(e -> finish(() -> onFailure.accept(task.getException()))); + AppExecutors.io().execute(task); + } + + private void finish(Runnable callback) { + try { + callback.run(); + } finally { + state.set(OperationState.IDLE); + } + } +} +``` + +`LoadingButtonBinder` å�ªè´Ÿè´£å±•示: + +```java +LoadingButtonBinder.bind( + exportButton, + exportAction.stateProperty(), + "开始导出", + "导出中…" +); +``` + +这样异常ã€�æ��å‰�返回和å�–消都ä¸�会é�—æ¼�æ�¢å¤�按钮。 + +### 2.3 推è��çš„æ�’件目录边界 + +```text +biz// + .java # æ�’件元数æ�®å’Œè£…é…� + application/ + .java # 一次用户任务的编排 + .java + .java + domain/ + ... # 纯业务模型和规则 + infrastructure/ + ... # Gitã€�DBã€�文件ã€�进程等外部访问 + ui/ + Pane.java # å�ªç»„装区域 + ViewModel.java # å�¯è§‚察状æ€�与命令 + components/ + ... +``` + +é™�制规则: + +- `Pane` ä¸�直接创建线程ã€�访问文件ã€�调用 Git/DB 或拼接业务结果。 +- `ViewModel` ä¸�创建 JavaFX 节点。 +- `UseCase` ä¸�ä¾�èµ– JavaFX。 +- 表格 cell ä¸�直接执行文件æ“�作,调用明确的 command。 +- å�•文件建议ä¸�超过 350 行;超过 500 行必须拆分。 +- æ¯�个异步æ“�作å�ªæœ‰ä¸€ä¸ªæ‹¥æœ‰è€…,ç¦�止窗å�£å’Œ Service å�Œæ—¶ç®¡ç�†çº¿ç¨‹ç”Ÿå‘½å‘¨æœŸã€‚ + +## 3. 主框架 + +è¯�æ�®ï¼š`screenshots/00-home.png` + +### UI 问题 + +- 欢迎页信æ�¯ä»·å€¼ä½Žï¼Œå¤§ç‰‡ç©ºç™½ï¼›æ²¡æœ‰æœ€è¿‘任务ã€�常用æ�’件或é…�ç½®å�¥åº·çжæ€�。 +- 顶部å�ªæœ‰é‡�å¤�çš„æ�’件图标和å��称,无法承载状æ€�ã€�帮助或全局通知。 +- 导航图标æ�¥æº�ä¸�统一,部分图标显示风格和宽度ä¸�一致。 +- æ�’件说明å�ªå­˜åœ¨å…ƒæ•°æ�®ä¸­ï¼Œå¯¼èˆªå’Œé¡µé�¢å†…没有有效呈现。 + +### é‡�æž„ + +- 欢迎页改为“最近使用 + é…�置状æ€� + å¿«æ�·å…¥å�£â€�,ä¸�è¦�é‡�å¤�罗列功能å��称。 +- `MainWindow` å�ªè´Ÿè´£è·¯ç”±ä¸Žå£³å±‚;拆出 `NavigationPane`ã€�`WorkspaceHeader`ã€�`WelcomePane`。 +- 增加统一 `NotificationCenter`,æ�’件错误使用页内 banner 或 toast,ä¸�è¦�å�„自弹 Alert。 +- 用图标库统一图标,ä¸�å†�把 Emoji 当 UI 图标。 + +## 4. Git 仓库å�Œæ­¥ + +è¯�æ�®ï¼š`screenshots/01-git-sync.png` + +### UI 问题 + +- 项目表直接展示å�«è´¦å�·çš„远程 URL,既æ•�感å�ˆå� æ�®å¤§é‡�宽度。 +- “Git …â€�列标题被截断,列宽策略失效。 +- 69 个项目没有æ�œç´¢ã€�状æ€�筛选和批é‡�选择å��馈。 +- “å�Œæ­¥æ‰§è¡Œâ€�和“æ�Ÿå��仓库处ç�†â€�以 Tab 分割,但用户无法看到å�Œæ­¥ä»»åŠ¡ä¸Žé¡¹ç›®é€‰æ‹©çš„å…³ç³»ã€‚ +- loading 主è¦�é� ç¦�用“å�Œæ­¥â€�å’Œå�¯ç”¨â€œå�œæ­¢â€�,缺少总进度ã€�当å‰�项目ã€�æˆ�功/失败计数。 + +### 设计 + +- 项目列表顶部:æ�œç´¢ã€�状æ€�筛选ã€�`已选择 N 项`。 +- URL 默认显示 `host/group/repo`,账å�·ä¿¡æ�¯æŽ©ç �;完整值仅通过“å¤�制地å�€â€�获得。 +- å�Œæ­¥æ“�作采用固定底部 ActionBar:`å�Œæ­¥é€‰ä¸­é¡¹ç›®` + æ�¡ä»¶æ˜¾ç¤º `å�œæ­¢`。 +- è¿�行时展示:总进度ã€�当å‰�仓库ã€�æˆ�功/跳过/失败计数;失败项留在结果列表。 +- “æ�Ÿå��仓库处ç�†â€�作为失败结果的å�Žç»­åŠ¨ä½œï¼Œè€Œä¸�是并列一级 Tab。 + +### 代ç �é‡�æž„ + +- `GitSyncWindow` 拆为 `ProjectTablePane`ã€�`SyncProgressPane`ã€�`DamagedRepoPane`。 +- 从 `GitSyncPlugin` 中è¿�出 Git 命令ã€�进程输出和 URL è§£æž�,形æˆ� `GitRepositoryGateway`。 +- `SyncRepositoriesUseCase` 返回结构化事件,ä¸�å�‘ UI 传原始日志字符串: + +```java +sealed interface SyncEvent { + record Started(int total) implements SyncEvent {} + record RepositoryStarted(String repository, int index) implements SyncEvent {} + record RepositoryFinished(String repository, SyncOutcome outcome) implements SyncEvent {} + record Completed(SyncSummary summary) implements SyncEvent {} +} +``` + +## 5. Git 分支评审 + +è¯�æ�®ï¼š`screenshots/02-git-review.png` + +### UI 问题 + +- 页é�¢ä¿¡æ�¯å¯†åº¦è¿‡é«˜ï¼Œâ€œç²˜è´´è¯†åˆ«â€�“手动字段â€�“IDEA 命令â€�“执行日志â€�å�Œæ—¶å‡ºçŽ°ã€‚ +- 主按钮“准备评审â€�å�«ä¹‰ä¸�明确,实际上会拉å�–ã€�切分支并打开 IDEA,副作用较大。 +- æ�¥æº�/目标ä¾�é�  Aã€�B 解释,用户ä»�容易å��å�‘æ“�作。 +- è¿�行时 `runButton` å’Œ `historyOpenButton` 被å�Œä¸€ `running` 状æ€�控制,两个无关动作耦å�ˆã€‚ +- 日志区默认空白,缺少阶段å¼�å��馈。 + +### 设计 + +- 改为三步:①识别评审信æ�¯ï¼›â‘¡ç¡®è®¤ä»“库和分支方å�‘;③执行并查看结果。 +- 主按钮文案明确为“切æ�¢åˆ°ç›®æ ‡åˆ†æ”¯å¹¶æ‰“开评审â€�。 +- 在执行å‰�展示摘è¦�:`æ�¥æº� A → 目标 B`ã€�将执行的 Git æ“�作ã€�工作区是å�¦å¹²å‡€ã€‚ +- æ¯�个æ“�作拥有独立状æ€�:识别ã€�刷新ã€�执行ã€�打开历å�²äº’ä¸�é”�死。 + +### 代ç �é‡�æž„ + +- `ReviewTextParser` 独立且纯函数化。 +- `GitReviewViewModel` æŒ�有表å�•å’Œ `reviewAction`。 +- `GitReviewService` 拆æˆ� `GitStatusReader`ã€�`BranchPreparationService`ã€�`IdeaLauncher`。 +- 用 `ReviewPlan` 表达执行å‰�计划,使 UI å�¯é¢„览,也便于å�•测。 + +## 6. 文本对比 + +è¯�æ�®ï¼š`screenshots/03-diff.png` + +### UI 问题 + +- 空状æ€�完全空白,没有示例或输入æ��示。 +- 结果区在未比较时ä»�å� æ�®å¤§å�Šé¡µé�¢ã€‚ +- “开始对比â€�对于本地 CPU æ“�作没有 loading;大文本å�¯èƒ½å†»ç»“ JavaFX 线程。 +- 上一处/下一处在无结果时å�ªæ˜¯ç�°è‰²ï¼Œæœªè§£é‡Šå·®å¼‚æ•°é‡�。 +- 原文/对比文缺少文件导入ã€�ç¼–ç �å’Œæ�¢è¡Œç¬¦ä¿¡æ�¯ã€‚ + +### 设计 + +- 输入区增加拖入文件/粘贴入å�£å’Œå­—符ã€�行数统计。 +- 首次使用显示简短示例;比较å�Žå°†ç»“果区扩展。 +- ActionBar 显示 `å�‘现 N 处差异`,导航按钮显示当å‰�ä½�ç½® `3/18`。 +- 大文本比较进入å�Žå�°ä»»åŠ¡ï¼ŒæŒ‰é’®æ˜¾ç¤ºâ€œæ¯”è¾ƒä¸­â€¦â€�,并支æŒ�å�–消。 + +### 代ç �é‡�æž„ + +- 当å‰� `DiffWindow` å�Œæ—¶åŒ…å�« LCSã€�字符分段ã€�HTML 渲染和 UI,应拆为: + - `DiffEngine` + - `DiffResult` + - `DiffHtmlRenderer` + - `DiffViewModel` + - `DiffPane` +- `DiffResult` ä¿�留结构化行和字符片段,UI ä¸�å†�è§£æž� HTML æ�¥å¯¼èˆªã€‚ + +## 7. MyBatis SQL 导出 + +è¯�æ�®ï¼š`screenshots/04-mybatis-export.png` + +### UI 问题 + +- “执行日志â€�在未执行时是空白大框;历å�²è¡¨å��而æˆ�为页é�¢è§†è§‰é‡�点。 +- “导出/终止â€�始终并列,终止按钮å�³ä½¿ç¦�用也æŒ�ç»­å� ä½�。 +- 缺少项目范围ã€�目标目录和预估数é‡�摘è¦�。 +- 历å�²è¡¨åˆ—标题被截断,文件å��过长,核心信æ�¯é𾿉«æ��。 +- loading 有进度文本,但没有进度æ�¡å’Œé”™è¯¯è®¡æ•°ã€‚ + +### 设计 + +- é…�ç½®å�¡æ˜¾ç¤ºè¿‡æ»¤æ�¡ä»¶ã€�项目范围ã€�输出目录。 +- 主按钮为“导出 SQLâ€�ï¼›è¿�行å�Žæ‰�出现“å�œæ­¢â€�。 +- 状æ€�区显示 `12/69`ã€�当å‰�项目ã€�已导出 SQL æ•°ã€�错误数。 +- 历å�²è®°å½•放第二 Tab,文件å��å�•行çœ�略,Tooltip 展示完整路径。 + +### 代ç �é‡�æž„ + +- `MyBatisExportWindow` å’Œ `ScannerWindow` 的历å�²è¡¨ã€�打开/目录è�œå�•高度é‡�å¤�,æ��å�– `ExportHistoryPane`。 +- 用 `ExportRequest` 替代多个散è�½å�‚数。 +- `MyBatisExportService` 通过 `ProgressSink` 上报结构化进度。 + +## 8. MyBatis 逆å�‘工程 + +è¯�æ�®ï¼š`screenshots/05-mybatis-generator.png` + +### UI 问题 + +- 顶部展示完整 JDBC URL 和用户å��,存在泄露风险。 +- 左侧项目树与å�³ä¾§è¡¨æŸ¥è¯¢ã€�输出目录并排,用户任务顺åº�ä¸�清。 +- 三个输出路径通常相关,å�´è¦�求é€�项æµ�览/填充。 +- “å�–消â€�实际是关闭窗å�£ï¼Œåœ¨åµŒå…¥æ¨¡å¼�下语义ä¸�æˆ�立。 +- 查询表和生æˆ�æ“�作没有统一 loading,也缺少连接失败å�Žçš„就地æ�¢å¤�。 + +### 设计 + +- 分æˆ� â‘ æ•°æ�®æº� ②选择表 ③生æˆ�é…�ç½® ④确认生æˆ� 四个区域或步骤。 +- æ•°æ�®æº�仅显示别å��ã€�æ•°æ�®åº“å��ã€�主机掩ç �和连接状æ€�,完整连接串å�ªåœ¨è®¾ç½®é¡µç»´æŠ¤ã€‚ +- 输出目录选择一个项目根目录,å†�实时预览三个派生目录。 +- “生æˆ�â€�å‰�显示将覆盖/创建的文件摘è¦�;完æˆ�å�Žå±•示文件列表和打开目录。 +- 嵌入模å¼�去掉“å�–消â€�,改为“é‡�ç½®é…�ç½®â€�。 + +### 代ç �é‡�æž„ + +- `GeneratorFormState` 统一æŒ�有表选择与目录规则。 +- `DatasourceSummary` 是脱æ•� DTO,UI ç¦�止接触密ç �和原始 URL。 +- `QueryTablesUseCase` 与 `GenerateArtifactsUseCase` 使用两个独立 `AsyncAction`。 +- 路径推导放入 `OutputLayoutPolicy`,é�¿å…�三个按钮å�„自维护逻辑。 + +## 9. 扫æ��功能 + +è¯�æ�®ï¼š`screenshots/06-scanner.png` + +### UI 问题 + +- 页é�¢å†™â€œæ‰«æ��类型:关键è¯�扫æ��â€�,但æ��述称支æŒ�关键è¯�/Redis/Dubbo,入å�£å’Œèƒ½åŠ›ä¸�一致。 +- 正则匹é…�å�ªæ˜¯ä¸€ä¸ª Checkbox,缺少风险æ��示和表达å¼�校验。 +- 当å‰�状æ€�å�ªæ˜¾ç¤ºâ€œå°±ç»ªâ€�,ä½�置和视觉æ�ƒé‡�过低。 +- 历å�²è¡¨æŠ¢å� ä¸»é¡µé�¢ï¼Œç©ºç™½ç»“æžœ/当å‰�任务没有清晰区分。 +- 开始扫æ��å�ªç¦�用按钮,ä¸�展示 spinnerã€�进度或å�–消能力。 + +### 设计 + +- 扫æ��类型使用å�•选å�¡æˆ–下拉,并根æ�®ç±»åž‹åˆ‡æ�¢ä¸“属字段。 +- 正则模å¼�æ��ä¾›å�³æ—¶æ ¡éªŒå’Œç¤ºä¾‹ã€‚ +- 执行区域展示扫æ��目录ã€�项目数ã€�匹é…�数和当å‰�项目。 +- 当å‰�结果与历å�²è®°å½•分 Tab。 +- 主按钮 loading 文案为“扫æ��中 12/69â€�,æ��ä¾›å�–消。 + +### 代ç �é‡�æž„ + +- å°† `ScanConfig` å�‡çº§ä¸ºæŒ‰ç±»åž‹åŒºåˆ†çš„ sealed request,é�¿å…�大é‡�å�¯ç©ºå­—段。 +- `ScannerService` ä¸�使用默认 `CompletableFuture` 线程池,统一注入å�—控 Executor。 +- `ScannerWindow` 与历å�²æ–‡ä»¶æ“�作解耦,å¤�用公共历å�²ç»„件。 + +## 10. API 接å�£æ–‡æ¡£å¯¼å‡º + +è¯�æ�®ï¼š`screenshots/07-api-doc.png` + +### UI 问题 + +- 三张模å¼�å�¡å� æ�®å¤§é‡�空间,但下方关键输入没有标签,ä¾�èµ– placeholder。 +- “全é™�定å��â€�“批é‡�导出â€�的说明文字对é�žä½œè€…用户ä¸�够明确。 +- 主按钮横跨整个页é�¢ï¼Œè§†è§‰é‡�é‡�过大。 +- 导出é…�ç½®ã€�导出历å�²ã€�基类é…�ç½®å�Œå±žä¸€çº§ Tab,但基类é…�置是低频系统设置。 +- 文件/目录选择也使用 loading,æ“�作通常瞬时完æˆ�,产生å�‡çš„忙碌感。 +- loading 通过节点属性ä¿�存旧文字,且部分代ç �å†�次直接覆盖文字,状æ€�æ�¥æº�ä¸�唯一。 + +### 设计 + +- 模å¼�切æ�¢æ”¹ä¸ºç´§å‡‘ Segmented Control。 +- æ¯�ç§�模å¼�å�ªæ˜¾ç¤ºç›¸å…³å­—段,并有明确 Labelã€�示例和校验错误。 +- 主按钮å�³å¯¹é½�,显示导出范围摘è¦�。 +- 基类é…�置移入系统设置或高级设置。 +- å�ªæœ‰è§£æž�/生æˆ�过程进入 loading;文件选择ä¸�显示 spinner。 +- 结果页显示生æˆ�文件ã€�接å�£æ•°ã€�方法数ã€�耗时和“打开/å¤�制路径â€�。 + +### 代ç �é‡�æž„ + +- `ApiDocWindow` 拆æˆ� `ExportConfigPane`ã€�`ExportHistoryPane`ã€�`BaseClassConfigPane`。 +- `ExportMode` å�„自实现 request 构造,é�¿å…� `startExport` 中按模å¼�分支。 +- `ApiDocExportUseCase` è´Ÿè´£ parse/generate/history,UI å�ªæ��交 `ApiDocExportRequest`。 +- 删除窗å�£å†… `setBtnLoading`,接入统一 `AsyncAction`。 +- HTML 调试代ç�†ä½œä¸ºå�•独能力开关,ä¸�在生æˆ� HTML æ—¶éš�å¼�å�¯åŠ¨ã€‚ + +## 11. 手机 UI 自动化 + +è¿�行时当å‰�ç¦�用,结论基于æº�ç �ï¼›ä¸�能作为截图å�¯éªŒè¯�çš„ UI 结论。 + +### 主è¦�问题 + +- `MobileUiAutomationWindow` 1702 行ã€�67 个方法ã€�30 个 actionã€�36 处线程/回调相关代ç �,是最高风险文件。 +- 环境安装ã€�设备管ç�†ã€�用例è¿�行ã€�录制ã€�截图轮询ã€�步骤编辑ã€�报告历å�²å…¨éƒ¨é›†ä¸­åœ¨ä¸€ä¸ªç±»ã€‚ +- 使用 `isRunning`ã€�按钮文字和内è�” style å…±å�Œè¡¨è¾¾çжæ€�,容易ä¸�一致。 +- 截图轮询拥有独立线程,窗å�£ç”Ÿå‘½å‘¨æœŸä¸Žçº¿ç¨‹å�œæ­¢é€»è¾‘难验è¯�。 +- “è¿�行/å�œæ­¢â€�和“开始录制/å�œæ­¢å¹¶ç”Ÿæˆ�用例â€�通过改文字å¤�用按钮,状æ€�机ä¸�明确。 + +### 设计 + +- 一级拆为“è¿�行用例â€�“录制用例â€�“环境与设备â€�三个页é�¢ã€‚ +- 顶部设备æ�¡å�ªæ˜¾ç¤ºå½“å‰�设备和å�¥åº·çжæ€�;安装工具放入环境页。 +- è¿�行页显示用例ã€�å�‚æ•°ã€�实时步骤和报告;录制页è�šç„¦æˆªå›¾ä¸Žæ­¥éª¤åˆ—表。 +- è¿�行和录制使用显å¼�状æ€�机,å�œæ­¢æŒ‰é’®ç‹¬ç«‹å‡ºçŽ°ã€‚ + +### 代ç �é‡�æž„ + +至少拆æˆ�: + +```text +mobileuiauto/ui/ + MobileAutomationPane.java + DeviceBar.java + run/RunCasePane.java + run/RunCaseViewModel.java + record/RecordCasePane.java + record/RecordCaseViewModel.java + environment/EnvironmentPane.java + environment/EnvironmentViewModel.java +``` + +新增两个状æ€�机: + +```java +enum RunState { IDLE, STARTING, RUNNING, STOPPING, SUCCEEDED, FAILED } +enum RecordState { IDLE, STARTING, RECORDING, GENERATING, FAILED } +``` + +截图轮询å°�装为 `ScreenshotStream extends AutoCloseable`,由录制 ViewModel æŒ�有并在页é�¢ç¦»å¼€æ—¶å…³é—­ã€‚ + +## 12. 系统设置 + +### UI 问题 + +- Tab æ•°é‡�多但缺少分类,é…�置文件编辑ä¾�赖外部编辑器。 +- “é‡�新加载â€�çš„å��馈ä¸�明确。 +- æ•°æ�®æº�ã€�项目路径ã€�æ�’件管ç�†æœ¬è´¨æ˜¯ç»“构化é…�置,ä¸�应主è¦�ä¾�赖文本文件。 + +### é‡�æž„ + +- 分类为“常规 / 项目与数æ�®æº� / æ�’ä»¶ / 外观â€�。 +- é…�置项使用表å�•å¹¶æ��供校验ã€�ä¿�å­˜æˆ�功状æ€�å’Œæ�¢å¤�默认。 +- 所有æ•�感字段支æŒ�显示/éš�è—�;列表页é�¢å�ªä½¿ç”¨è„±æ•� DTO。 + +## 13. 建议实施顺åº� + +1. 建立 `OperationState`ã€�`AsyncAction`ã€�`LoadingButtonBinder`ã€�`OperationStatusPane`。 +2. æ��å�– `ExportHistoryPane`ã€�`EmptyStatePane`ã€�`NotificationCenter`。 +3. å…ˆè¿�ç§» Scanner å’Œ MyBatis SQL 导出,验è¯�公共组件。 +4. è¿�ç§» API 文档导出和 MyBatis 逆å�‘工程。 +5. 拆分 Git å�Œæ­¥å’Œ Git 评审。 +6. 抽离 DiffEngine。 +7. 最å�Žå�•独é‡�构手机 UI 自动化,ä¸�与其他æ�’件并行大改。 + +## 14. AI å�‹å¥½ç¼–ç �约æ�Ÿ + +- æ¯�个需求先定ä½�到一个 UseCase 和一个 ViewModel,é�¿å…�直接修改 Window。 +- ä¸�å…�许新增裸 `new Thread`。 +- ä¸�å…�许在业务代ç �直接调用 `Button#setText/setDisable/setGraphic`。 +- ä¸�å…�许使用 `Node#getProperties()` ä¿�存业务状æ€�。 +- ä¸�å…�许在 Window 中出现 Gitã€�SQLã€�HTTPã€�进程命令或文件é��历。 +- 所有跨线程结果必须是ä¸�å�¯å�˜ DTO。 +- 所有状æ€�使用 enum,ä¸�使用多个 boolean 拼状æ€�。 +- æ¯�个 ViewModel 为æ¯�个 action æ��供独立状æ€�,ç¦�止一个 `running` é”�ä½�无关按钮。 +- 为 Request 校验ã€�状æ€�è¿�ç§»ã€�UseCase æˆ�功/失败/å�–消路径编写å�•元测试。 +- UI 测试å�ªéªŒè¯�绑定和å�¯è§�性,ä¸�é‡�å¤�测试业务逻辑。 + +## 15. è¯�æ�®èŒƒå›´ + +已实际æ�•获并å¤�核:主界é�¢ã€�Git å�Œæ­¥ã€�Git 分支评审ã€�文本对比ã€�MyBatis SQL 导出ã€�MyBatis 逆å�‘工程ã€�扫æ��ã€�API 文档导出。 + +未实际触å�‘具有副作用的å�Œæ­¥ã€�切分支ã€�æ•°æ�®åº“查询ã€�生æˆ�ã€�导出和删除æ“�作,因此 loadingã€�å�–消ã€�错误æ�¢å¤�的结论å�Œæ—¶å�‚考了æº�ç �。手机 UI 自动化因当å‰�é…�ç½®ç¦�用,仅完æˆ�æº�ç �审查。截图ä¸�能è¯�明完整键盘访问ã€�焦点顺åº�ã€�å±�幕阅读器语义或颜色对比å�ˆè§„,这些需è¦�专项测试。 diff --git a/docs/audit/screenshots/00-home.png b/docs/audit/screenshots/00-home.png new file mode 100644 index 0000000..ef5a08d Binary files /dev/null and b/docs/audit/screenshots/00-home.png differ diff --git a/docs/audit/screenshots/01-git-sync.png b/docs/audit/screenshots/01-git-sync.png new file mode 100644 index 0000000..135d6a3 Binary files /dev/null and b/docs/audit/screenshots/01-git-sync.png differ diff --git a/docs/audit/screenshots/02-git-review.png b/docs/audit/screenshots/02-git-review.png new file mode 100644 index 0000000..751d122 Binary files /dev/null and b/docs/audit/screenshots/02-git-review.png differ diff --git a/docs/audit/screenshots/03-diff.png b/docs/audit/screenshots/03-diff.png new file mode 100644 index 0000000..3a8ea3e Binary files /dev/null and b/docs/audit/screenshots/03-diff.png differ diff --git a/docs/audit/screenshots/04-mybatis-export.png b/docs/audit/screenshots/04-mybatis-export.png new file mode 100644 index 0000000..67fcc59 Binary files /dev/null and b/docs/audit/screenshots/04-mybatis-export.png differ diff --git a/docs/audit/screenshots/05-mybatis-generator.png b/docs/audit/screenshots/05-mybatis-generator.png new file mode 100644 index 0000000..0fee459 Binary files /dev/null and b/docs/audit/screenshots/05-mybatis-generator.png differ diff --git a/docs/audit/screenshots/06-scanner.png b/docs/audit/screenshots/06-scanner.png new file mode 100644 index 0000000..89c8b0f Binary files /dev/null and b/docs/audit/screenshots/06-scanner.png differ diff --git a/docs/audit/screenshots/07-api-doc.png b/docs/audit/screenshots/07-api-doc.png new file mode 100644 index 0000000..e6581aa Binary files /dev/null and b/docs/audit/screenshots/07-api-doc.png differ diff --git a/src/main/java/com/example/workutils/biz/aitest/AiTestPane.java b/src/main/java/com/example/workutils/biz/aitest/AiTestPane.java index 3e87d8f..c9ed8f9 100644 --- a/src/main/java/com/example/workutils/biz/aitest/AiTestPane.java +++ b/src/main/java/com/example/workutils/biz/aitest/AiTestPane.java @@ -1,6 +1,7 @@ package com.example.workutils.biz.aitest; import com.example.workutils.biz.aitest.application.AiTestProgress; +import com.example.workutils.biz.aitest.application.AiTestOneClickRunner; import com.example.workutils.biz.aitest.application.AiTestHistoryService; import com.example.workutils.biz.aitest.application.AiTestRunSummary; import com.example.workutils.biz.aitest.application.AiTestRequest; @@ -18,6 +19,7 @@ import com.example.workutils.biz.aitest.project.MavenProjectAnalyzer; import com.example.workutils.biz.aitest.project.MavenProjectModel; import com.example.workutils.biz.aitest.project.ModuleLoadPresentation; import com.example.workutils.biz.aitest.ui.DirectoryPathSelector; +import com.example.workutils.biz.aitest.ui.AiTestResultSelection; import com.example.workutils.biz.aitest.ui.TaskProgressState; import com.example.workutils.system.support.AppExecutors; import javafx.application.Platform; @@ -43,6 +45,7 @@ public class AiTestPane extends BorderPane { private final AiTestModulePreferenceService modulePreferences; private final AiTestHistoryService historyService; private final ToolchainValidator toolchainValidator; + private final AiTestOneClickRunner oneClickRunner; private final ComboBox projectCombo = new ComboBox<>(); private final ComboBox moduleCombo = new ComboBox<>(); @@ -58,8 +61,8 @@ public class AiTestPane extends BorderPane { private final Spinner repairRounds = new Spinner<>(1, 10, 3); private final TextArea defaultSpecification = new TextArea(); private final TextArea projectSpecification = new TextArea(); - private final Button analyzeButton = new Button("分æž�增é‡�"); - private final Button generateButton = new Button("生æˆ�并验è¯�"); + private final Button analyzeButton = new Button("仅分æž�增é‡�"); + private final Button generateButton = new Button("生æˆ�å�•测并分æž�覆盖率"); private final Button cancelButton = new Button("å�–消"); private final Button integrateButton = new Button("å�ˆå¹¶åˆ°æœ¬åœ°åˆ†æ”¯"); private final ProgressBar progressBar = new ProgressBar(0); @@ -67,6 +70,10 @@ public class AiTestPane extends BorderPane { private final Label moduleStatusLabel = new Label("请选择项目"); private final Label toolchainStatus = new Label("工具链未检查"); private final TabPane resultTabs = new TabPane(); + private final TabPane mainTabs = new TabPane(); + private Tab resultsMainTab; + private Tab coverageResultTab; + private Tab logResultTab; private final ListView generatedTests = new ListView<>(); private final TextArea coverageArea = readOnlyArea(); private final TextArea logArea = readOnlyArea(); @@ -94,6 +101,7 @@ public class AiTestPane extends BorderPane { this.modulePreferences = modulePreferences; this.historyService = historyService; this.toolchainValidator = toolchainValidator; + this.oneClickRunner = new AiTestOneClickRunner(workflow); buildUi(); bindActions(); loadInitialData(); @@ -103,13 +111,17 @@ public class AiTestPane extends BorderPane { setPadding(new Insets(20)); setCenter(buildContent()); setBottom(buildStatus()); - generateButton.setDisable(true); + generateButton.setDisable(false); integrateButton.setDisable(true); cancelButton.setDisable(true); projectCombo.setMaxWidth(Double.MAX_VALUE); moduleCombo.setMaxWidth(Double.MAX_VALUE); baselineField.setId("baseline-ref"); targetRefField.setId("target-ref"); + analyzeButton.setId("analyze-only-action"); + generateButton.setId("generate-and-cover-action"); + mainTabs.setId("ai-test-main-tabs"); + resultTabs.setId("ai-test-result-tabs"); projectCombo.setCellFactory(ignored -> projectCell()); projectCombo.setButtonCell(projectCell()); } @@ -120,7 +132,9 @@ public class AiTestPane extends BorderPane { addRow(selection, 1, "基线分支/Commit", baselineField, "目标分支/Commit", targetRefField); selection.add(includeWorkingTree, 1, 2); selection.add(moduleStatusLabel, 3, 2, 2, 1); - VBox projectPage = page(selection); + HBox projectActions = new HBox(10, generateButton, analyzeButton, cancelButton); + projectActions.setAlignment(Pos.CENTER_LEFT); + VBox projectPage = page(selection, projectActions); GridPane toolchain = grid(); Button validateToolchain = new Button("检查并ä¿�存工具链"); @@ -141,22 +155,23 @@ public class AiTestPane extends BorderPane { VBox specificationPage = page(specifications, saveSpecifications); VBox.setVgrow(specifications, Priority.ALWAYS); - resultTabs.getTabs().addAll(tab("生æˆ�文件", generatedTests), tab("覆盖率", coverageArea), - tab("è¿�行日志", logArea), tab("历å�²æ‘˜è¦�", historyArea)); + coverageResultTab = tab("覆盖率", coverageArea); + logResultTab = tab("è¿�行日志", logArea); + resultTabs.getTabs().addAll(tab("生æˆ�文件", generatedTests), coverageResultTab, + logResultTab, tab("历å�²æ‘˜è¦�", historyArea)); resultTabs.setTabClosingPolicy(TabPane.TabClosingPolicy.UNAVAILABLE); VBox.setVgrow(resultTabs, Priority.ALWAYS); - HBox actions = new HBox(10, analyzeButton, generateButton, cancelButton); - actions.setAlignment(Pos.CENTER_LEFT); GridPane integration = grid(); addRow(integration, 0, "目标本地分支", targetBranch, "æ��交信æ�¯", commitMessage); integration.add(reviewApproved, 0, 1, 2, 1); integration.add(integrateButton, 4, 1); - VBox resultPage = page(actions, resultTabs, titled("审核并å�ˆå¹¶", integration)); + VBox resultPage = page(resultTabs, titled("审核并å�ˆå¹¶", integration)); VBox.setVgrow(resultTabs, Priority.ALWAYS); - TabPane mainTabs = new TabPane(tab("项目与增é‡�", projectPage), tab("工具链", toolchainPage), - tab("è´¨é‡�规范", specificationPage), tab("结果与å�ˆå¹¶", resultPage)); + resultsMainTab = tab("结果与å�ˆå¹¶", resultPage); + mainTabs.getTabs().addAll(tab("项目与增é‡�", projectPage), tab("工具链", toolchainPage), + tab("è´¨é‡�规范", specificationPage), resultsMainTab); mainTabs.setTabClosingPolicy(TabPane.TabClosingPolicy.UNAVAILABLE); return mainTabs; } @@ -184,7 +199,7 @@ public class AiTestPane extends BorderPane { } }); analyzeButton.setOnAction(event -> analyze()); - generateButton.setOnAction(event -> generate()); + generateButton.setOnAction(event -> generateAndCover()); cancelButton.setOnAction(event -> workflow.cancel()); integrateButton.setOnAction(event -> integrate()); reviewApproved.selectedProperty().addListener((ignored, oldValue, approved) -> updateButtons()); @@ -271,28 +286,46 @@ public class AiTestPane extends BorderPane { } private void analyze() { - AiTestProject project = projectCombo.getValue(); - MavenModule module = moduleCombo.getValue(); - if (project == null || module == null || baselineField.getText().isBlank() - || targetRefField.getText().isBlank()) { - statusLabel.setText("请选择项目ã€�模å�—并填写基线和目标引用"); + AiTestRequest request = requestFromForm(); + if (request == null) { return; } - AiTestRequest request = new AiTestRequest(project.path(), module.artifactId(), - baselineField.getText().trim(), targetRefField.getText().trim(), - includeWorkingTree.isSelected(), settingsFromForm()); runAsync(() -> workflow.analyze(request, this::onProgress), run -> { currentRun = run; renderRun(run); }); } - private void generate() { - AiTestRun analyzed = currentRun; - if (analyzed == null || analyzed.state() != AiTestRunState.ANALYZED) { + private AiTestRequest requestFromForm() { + AiTestProject project = projectCombo.getValue(); + MavenModule module = moduleCombo.getValue(); + if (project == null || module == null || baselineField.getText().isBlank() + || targetRefField.getText().isBlank()) { + statusLabel.setText("请选择项目ã€�模å�—并填写基线和目标引用"); + return null; + } + return new AiTestRequest(project.path(), module.artifactId(), + baselineField.getText().trim(), targetRefField.getText().trim(), + includeWorkingTree.isSelected(), settingsFromForm()); + } + + private void generateAndCover() { + AiTestRequest request = requestFromForm(); + if (request == null) { return; } - runAsync(() -> workflow.generateAndVerify(analyzed, this::onProgress), run -> { + runAsync(() -> { + ToolchainValidation validation = toolchainValidator.validate(request.settings(), ignored -> { }); + if (!validation.ready()) { + String failures = validation.checks().stream() + .filter(check -> !check.successful()) + .map(check -> check.name() + ": " + check.detail()) + .reduce("", (left, right) -> left + right + "\n"); + throw new IllegalStateException("工具链检查失败,请在‘工具链’中修正é…�置:\n" + + failures.trim()); + } + return oneClickRunner.run(request, this::onProgress); + }, run -> { currentRun = run; renderRun(run); }); @@ -323,6 +356,14 @@ public class AiTestPane extends BorderPane { historyArea.appendText(run.id() + " | " + run.state() + " | " + run.message() + "\n"); progressBar.setProgress(run.state() == AiTestRunState.READY_FOR_REVIEW || run.state() == AiTestRunState.SUCCEEDED ? 1 : 0); + if (run.state() == AiTestRunState.READY_FOR_REVIEW || run.state() == AiTestRunState.SUCCEEDED + || run.state() == AiTestRunState.FAILED || run.state() == AiTestRunState.CANCELLED) { + mainTabs.getSelectionModel().select(resultsMainTab); + AiTestResultSelection selection = AiTestResultSelection.forState(run.state()); + resultTabs.getSelectionModel().select(selection == AiTestResultSelection.COVERAGE + ? coverageResultTab : selection == AiTestResultSelection.LOG + ? logResultTab : resultTabs.getTabs().get(0)); + } updateButtons(); } @@ -353,6 +394,8 @@ public class AiTestPane extends BorderPane { statusLabel.setText(failure.getMessage() == null ? failure.getClass().getSimpleName() : failure.getMessage()); appendLog("失败: " + statusLabel.getText()); + mainTabs.getSelectionModel().select(resultsMainTab); + resultTabs.getSelectionModel().select(logResultTab); }); } }); @@ -390,8 +433,7 @@ public class AiTestPane extends BorderPane { private void updateButtons() { analyzeButton.setDisable(busy); - generateButton.setDisable(busy || currentRun == null - || currentRun.state() != AiTestRunState.ANALYZED); + generateButton.setDisable(busy); integrateButton.setDisable(busy || !reviewApproved.isSelected() || currentRun == null || currentRun.state() != AiTestRunState.READY_FOR_REVIEW); } diff --git a/src/main/java/com/example/workutils/biz/aitest/application/AiTestOneClickRunner.java b/src/main/java/com/example/workutils/biz/aitest/application/AiTestOneClickRunner.java new file mode 100644 index 0000000..ea4afb6 --- /dev/null +++ b/src/main/java/com/example/workutils/biz/aitest/application/AiTestOneClickRunner.java @@ -0,0 +1,19 @@ +package com.example.workutils.biz.aitest.application; + +import java.util.Objects; +import java.util.function.Consumer; + +public final class AiTestOneClickRunner { + private final AiTestWorkflow workflow; + + public AiTestOneClickRunner(AiTestWorkflow workflow) { + this.workflow = Objects.requireNonNull(workflow, "workflow"); + } + + public AiTestRun run(AiTestRequest request, Consumer progress) { + AiTestRun analyzed = workflow.analyze(request, progress); + return analyzed.state() == AiTestRunState.ANALYZED + ? workflow.generateAndVerify(analyzed, progress) + : analyzed; + } +} diff --git a/src/main/java/com/example/workutils/biz/aitest/ui/AiTestResultSelection.java b/src/main/java/com/example/workutils/biz/aitest/ui/AiTestResultSelection.java new file mode 100644 index 0000000..5e46c41 --- /dev/null +++ b/src/main/java/com/example/workutils/biz/aitest/ui/AiTestResultSelection.java @@ -0,0 +1,17 @@ +package com.example.workutils.biz.aitest.ui; + +import com.example.workutils.biz.aitest.application.AiTestRunState; + +public enum AiTestResultSelection { + GENERATED_FILES, + COVERAGE, + LOG; + + public static AiTestResultSelection forState(AiTestRunState state) { + return switch (state) { + case READY_FOR_REVIEW, SUCCEEDED -> COVERAGE; + case FAILED, CANCELLED -> LOG; + default -> GENERATED_FILES; + }; + } +} diff --git a/src/main/resources/投ä¿�-评审修改.sql b/src/main/resources/投ä¿�-评审修改.sql new file mode 100644 index 0000000..961b666 --- /dev/null +++ b/src/main/resources/投ä¿�-评审修改.sql @@ -0,0 +1,355 @@ +alter table risk_compensatory_contract_info + add column contract_type varchar(32) not null default 'GUARANTEE' comment 'ºÏÔ¼ÀàÐÍ£»¼ûö¾Ù£ºcom.bestpay.ft.compensatory.core.api.contract.enums.ContractTypeEnum'; + +alter table risk_compensatory_order_info + add column compensatory_contract_no varchar(64) not null default '' comment '´ú³¥ºÏÔ¼ºÅ', + add column loan_status varchar(32) not null default '' comment '½è¾Ý״̬£»¼ûö¾Ù£ºcom.bestpay.ft.compensatory.core.common.enums.compensatory.LoanStatusEnum', + add column insurance_flag varchar(32) not null default '' comment 'Ͷ±£±êʶ£»¼ûö¾Ù£ºcom.bestpay.ft.compensatory.core.common.enums.compensatory.InsuranceFlagEnum', + add column area_code varchar(64) not null default '' comment 'ÇøÓò±àÂ룻ʡ±àÂ룻ALL=ËùÓУ¬ÉϺ£¡¢¹ã¶«...', + add column period_num int default null comment 'ÆÚÊýÊýÁ¿£»ÆÚÊý', + add column terminate_time datetime default null comment '½áÇåʱ¼ä'; + +create table `risk_insurance_contract_info` +( + `id` bigint(20) unsigned not null auto_increment comment 'Ö÷¼üid', + `created_at` datetime not null comment '´´½¨Ê±¼ä', + `created_by` varchar(128) not null default 'sys' comment '´´½¨ÈË', + `updated_at` datetime default null comment '¸üÐÂʱ¼ä', + `updated_by` varchar(128) not null default '' comment '¸üÐÂÈË', + `archived_at` datetime default null comment '¹éµµÊ±¼ä', + `archived_by` varchar(128) not null default '' comment '¹éµµÈË', + `archived_flag` tinyint(4) not null default '0' comment '¹éµµ±êʶ£º0=δ¹éµµ£¬1=Òѹ鵵', + `env` varchar(32) not null default '' comment '»·¾³±êʶ£¬ÓÃÓÚ±êʶÐмǼÊý¾ÝÀ´Ô´»·¾³¡£ÆäÖÐÈ«Á¿Ã¶¾Ù£ºÏßÏ£ºDEV(¿ª·¢»·¾³)£¬SIT(¼¯³É²âÊÔ»·¾³)£¬STB(Îȶ¨»·¾³)£»ÏßÉÏ£ºPRE(Ô¤·¢»·¾³)£¬GRY(»Ò¶È»·¾³)£¬PRD(Éú²ú»·¾³)', + `shadow` tinyint(4) not null default '0' comment 'Ó°×Ó±êʶλ (1 Ó°×ÓÊý¾Ý 0 ·ÇÓ°×ÓÊý¾Ý)', + `enabled_flag` tinyint(4) not null default '0' comment 'ÆôÓñêʶ£º0=δÆôÓã¬1=ÒÑÆôÓÃ', + `checked_at` datetime default null comment 'ÉóºËʱ¼ä', + `checked_by` varchar(128) not null default '' comment 'ÉóºËÈË', + `config_changed_flag` tinyint(4) not null default '0' comment 'ÅäÖñä¸ü±êʶ£º0=²»´æÔÚ´ýÉóºË£¬1=´æÔÚ´ýÉóºË', + `compensatory_contract_no` varchar(64) not null default '' comment '´ú³¥ºÏÔ¼±àºÅ', + `insurer_org_ip_r_id` varchar(64) not null default '' comment '±£ÏÕÈË»ú¹¹iprid', + `applicant_org_ip_r_id` varchar(64) not null default '' comment 'Ͷ±£ÈË»ú¹¹iprid', + `insurance_mode` varchar(32) not null default '' comment 'Ͷ±£Ä£Ê½£»¼ûö¾Ù£ºcom.bestpay.ft.compensatory.core.api.contract.enums.InsuranceModeEnum', + `insurance_amount_basis` varchar(32) not null default '' comment '±£ÏÕ½ð¶î»ù×¼£»¼ûö¾Ù£ºcom.bestpay.ft.compensatory.core.api.contract.enums.InsuranceAmountBasisEnum', + `insurance_cost_calculate_rule` varchar(128) not null default '' comment '±£·Ñ¼ÆËã¹æÔò£»¼ûö¾Ù£ºcom.bestpay.ft.compensatory.core.api.contract.enums.InsuranceCostCalculateRuleEnum', + `insurance_cost_calculate_rounding_mode` varchar(32) not null default '' comment '±£·Ñ¼ÆËãÉáλģʽ£»¼ûö¾Ù£ºcom.bestpay.ft.compensatory.core.api.contract.enums.InsuranceCostCalculateRoundingModeEnum', + `insurance_flow_cfg_code` varchar(64) not null default '' comment 'Ͷ±£Á÷³ÌÅäÖñí±àÂë', + `pack_day` varchar(32) not null default '' comment '´ò°üÈÕ£»¸ñʽ£ºDD', + `pack_frequency` varchar(128) not null default '' comment '´ò°üƵÂÊ£»¼ûö¾Ù£ºcom.bestpay.ft.compensatory.core.api.contract.enums.PackFrequencyEnum', + `pack_basis` varchar(128) not null default '' comment '´ò°ü»ù×¼£»¼ûö¾Ù£ºcom.bestpay.ft.compensatory.core.api.contract.enums.PackBasisEnum', + `pack_rule` varchar(32) not null default '' comment '´ò°ü¹æÔò£»¼ûö¾Ù£ºcom.bestpay.ft.compensatory.core.api.contract.enums.PackRuleEnum', + PRIMARY KEY (`id`), + KEY `idx_compensatory_contract_no` (`compensatory_contract_no`), + KEY `idx_insurance_flow_cfg_code` (`insurance_flow_cfg_code`) +) default charset=utf8mb4 comment='Ͷ±£ºÏÔ¼ÐÅÏ¢±í'; + +create table `risk_insurance_flow_cfg` +( + `id` bigint(20) unsigned not null auto_increment comment 'Ö÷¼üid', + `created_at` datetime not null comment '´´½¨Ê±¼ä', + `created_by` varchar(128) not null default 'sys' comment '´´½¨ÈË', + `updated_at` datetime default null comment '¸üÐÂʱ¼ä', + `updated_by` varchar(128) not null default '' comment '¸üÐÂÈË', + `archived_at` datetime default null comment '¹éµµÊ±¼ä', + `archived_by` varchar(128) not null default '' comment '¹éµµÈË', + `archived_flag` tinyint(4) not null default '0' comment '¹éµµ±êʶ£º0=δ¹éµµ£¬1=Òѹ鵵', + `env` varchar(32) not null default '' comment '»·¾³±êʶ£¬ÓÃÓÚ±êʶÐмǼÊý¾ÝÀ´Ô´»·¾³¡£ÆäÖÐÈ«Á¿Ã¶¾Ù£ºÏßÏ£ºDEV(¿ª·¢»·¾³)£¬SIT(¼¯³É²âÊÔ»·¾³)£¬STB(Îȶ¨»·¾³)£»ÏßÉÏ£ºPRE(Ô¤·¢»·¾³)£¬GRY(»Ò¶È»·¾³)£¬PRD(Éú²ú»·¾³)', + `shadow` tinyint(4) not null default '0' comment 'Ó°×Ó±êʶλ (1 Ó°×ÓÊý¾Ý 0 ·ÇÓ°×ÓÊý¾Ý)', + `enabled_flag` tinyint(4) not null default '0' comment 'ÆôÓñêʶ£º0=δÆôÓã¬1=ÒÑÆôÓÃ', + `checked_by` varchar(128) not null default '' comment 'ÉóºËÈË', + `checked_at` datetime default null comment 'ÉóºËʱ¼ä', + `config_changed_flag` tinyint(4) not null default '0' comment 'ÅäÖñä¸ü±êʶ£»0=²»´æÔÚ´ýÉóºË£¬1=´æÔÚ´ýÉóºË', + `flow_code` varchar(128) not null default '' comment 'Á÷³Ì±àºÅ', + `flow_name` varchar(128) not null default '' comment 'Á÷³ÌÃû³Æ', + `flow_desc` varchar(512) not null default '' comment 'Á÷³ÌÃèÊö', + PRIMARY KEY (`id`), + KEY `idx_flow_code` (`flow_code`) +) default charset=utf8mb4 comment='·çÏÕͶ±£Á÷³ÌÅäÖñí'; + +create table `risk_insurance_flow_node_cfg` +( + `id` bigint(20) unsigned not null auto_increment comment 'Ö÷¼üid', + `created_at` datetime not null comment '´´½¨Ê±¼ä', + `created_by` varchar(128) not null default 'sys' comment '´´½¨ÈË', + `updated_at` datetime default null comment '¸üÐÂʱ¼ä', + `updated_by` varchar(128) not null default '' comment '¸üÐÂÈË', + `archived_at` datetime default null comment '¹éµµÊ±¼ä', + `archived_by` varchar(128) not null default '' comment '¹éµµÈË', + `archived_flag` tinyint(4) not null default '0' comment '¹éµµ±êʶ£º0=δ¹éµµ£¬1=Òѹ鵵', + `env` varchar(32) not null default '' comment '»·¾³±êʶ£¬ÓÃÓÚ±êʶÐмǼÊý¾ÝÀ´Ô´»·¾³¡£ÆäÖÐÈ«Á¿Ã¶¾Ù£ºÏßÏ£ºDEV(¿ª·¢»·¾³)£¬SIT(¼¯³É²âÊÔ»·¾³)£¬STB(Îȶ¨»·¾³)£»ÏßÉÏ£ºPRE(Ô¤·¢»·¾³)£¬GRY(»Ò¶È»·¾³)£¬PRD(Éú²ú»·¾³)', + `shadow` tinyint(4) not null default '0' comment 'Ó°×Ó±êʶλ (1 Ó°×ÓÊý¾Ý 0 ·ÇÓ°×ÓÊý¾Ý)', + `enabled_flag` tinyint(4) not null default '0' comment 'ÆôÓñêʶ£º0=δÆôÓã¬1=ÒÑÆôÓÃ', + `checked_by` varchar(128) not null default '' comment 'ÉóºËÈË', + `checked_at` datetime default null comment 'ÉóºËʱ¼ä', + -- TODO ×Ö¶Î×¢ÊͲ¹³äö¾Ù£» + `flow_code` varchar(64) not null default '' comment 'Á÷³Ì±àºÅ', + `node_code` varchar(64) not null default '' comment '½Úµã±àÂë', + `node_name` varchar(128) not null default '' comment '½ÚµãÃû³Æ', + `node_interaction_way` varchar(32) not null default '' comment '½Úµã½»»¥·½Ê½£º¼ûö¾Ù£ºcom.bestpay.ft.compensatory.core.common.enums.compensatory.NodeInteractionWayEnum', + `node_interaction_config_value` varchar(64) not null default '' comment '½Úµã½»»¥ÅäÖÃÖµ', + `next_node_code` varchar(64) not null default '' comment 'ϸö½Úµã±àºÅ', + PRIMARY KEY (`id`), + KEY `idx_flow_code` (`flow_code`), + KEY `idx_node_code` (`node_code`) +) default charset=utf8mb4 comment='·çÏÕͶ±£Á÷³Ì½ÚµãÅäÖñí'; + +create table `risk_insurance_contract_insurance_cost_rate_cfg` +( + `id` bigint(20) unsigned not null auto_increment comment 'Ö÷¼üid', + `created_at` datetime not null comment '´´½¨Ê±¼ä', + `created_by` varchar(128) not null default 'sys' comment '´´½¨ÈË', + `updated_at` datetime default null comment '¸üÐÂʱ¼ä', + `updated_by` varchar(128) not null default '' comment '¸üÐÂÈË', + `archived_at` datetime default null comment '¹éµµÊ±¼ä', + `archived_by` varchar(128) not null default '' comment '¹éµµÈË', + `archived_flag` tinyint(4) not null default '0' comment '¹éµµ±êʶ£º0=δ¹éµµ£¬1=Òѹ鵵', + `env` varchar(32) not null default '' comment '»·¾³±êʶ£¬ÓÃÓÚ±êʶÐмǼÊý¾ÝÀ´Ô´»·¾³¡£ÆäÖÐÈ«Á¿Ã¶¾Ù£ºÏßÏ£ºDEV(¿ª·¢»·¾³)£¬SIT(¼¯³É²âÊÔ»·¾³)£¬STB(Îȶ¨»·¾³)£»ÏßÉÏ£ºPRE(Ô¤·¢»·¾³)£¬GRY(»Ò¶È»·¾³)£¬PRD(Éú²ú»·¾³)', + `shadow` tinyint(4) not null default '0' comment 'Ó°×Ó±êʶλ (1 Ó°×ÓÊý¾Ý 0 ·ÇÓ°×ÓÊý¾Ý)', + `enabled_flag` tinyint(4) not null default '0' comment 'ÆôÓñêʶ£º0=δÆôÓã¬1=ÒÑÆôÓÃ', + `checked_by` varchar(128) not null default '' comment 'ÉóºËÈË', + `checked_at` datetime default null comment 'ÉóºËʱ¼ä', + `compensatory_contract_no` varchar(64) not null default '' comment '´ú³¥ºÏÔ¼ºÅ', + `area_code` varchar(64) not null default '' comment 'ÇøÓò±àÂ룻ʡ±àÂ룻ALL=ËùÓУ¬ÉϺ£¡¢¹ã¶«...', + `area_name` varchar(64) not null default '' comment 'ÇøÓòÃû³Æ£»Ê¡Ãû³Æ', + `period_num` int default null comment 'ÆÚÊýÊýÁ¿£ºALL=ËùÓУ¬12¡¢24...', + `insurance_cost_rate` varchar(32) not null default '' comment '±£·Ñ·ÑÂÊ£»Íò·Öλ', + PRIMARY KEY (`id`), + KEY `idx_compensatory_contract_no` (`compensatory_contract_no`) +) default charset=utf8mb4 comment='Ͷ±£ºÏÔ¼±£·Ñ·ÑÂÊÅäÖñí'; + +------TODO ÆÀÉóID£º +create table `risk_insurance_evt` +( + `id` bigint(20) unsigned not null auto_increment comment 'Ö÷¼üid', + `created_at` datetime not null comment '´´½¨Ê±¼ä', + `created_by` varchar(128) not null default 'sys' comment '´´½¨ÈË', + `updated_at` datetime default null comment '¸üÐÂʱ¼ä', + `updated_by` varchar(128) not null default '' comment '¸üÐÂÈË', + `archived_at` datetime default null comment '¹éµµÊ±¼ä', + `archived_by` varchar(128) not null default '' comment '¹éµµÈË', + `archived_flag` tinyint(4) not null default '0' comment '¹éµµ±êʶ£º0=δ¹éµµ£¬1=Òѹ鵵', + `env` varchar(32) not null default '' comment '»·¾³±êʶ£¬DEV/SIT/STB/PRE/GRY/PRD', + `shadow` tinyint(4) not null default '0' comment 'Ó°×Ó±êʶλ (1 Ó°×ÓÊý¾Ý 0 ·ÇÓ°×ÓÊý¾Ý)', + `tnt_id` varchar(64) not null default '' comment '×â»§id', + `product_line_code` varchar(64) not null default '' comment '²úÆ·Ïß±àÂë', + `biz_no` varchar(64) not null default '' comment 'ÉÏÓÎÒµÎñµ¥ºÅ£»¸ù¾ÝʼþÀàÐͲ»Ò»Ñù£¬±ÈÈç´ò°üͶ±£µ¥£¬¼Ç¼´ú³¥Ö´ÐÐÈÎÎñÅú´ÎºÅ', + `req_time` datetime not null comment 'ÇëÇóʱ¼ä', + `req_id` varchar(64) not null default '' comment 'ÇëÇóÁ÷Ë®ºÅ', + `evt_type` varchar(32) not null default '' comment 'ʼþÀàÐÍ£»¼ûö¾Ù£ºcom.bestpay.ft.compensatory.core.api.insurance.enums.InsuranceEvtTypeEnum', + `node_code` varchar(64) not null default '' comment '½Úµã±àÂë', + `request_system` varchar(32) not null default '' comment 'ÇëÇóϵͳ', +-- TODO ²¹³ä£º¼ûö¾Ù + `operator_type` varchar(32) not null default '' comment '²Ù×÷ÈËÀàÐÍ£º¼ûö¾Ù£º', + `operator_id` varchar(128) not null default '' comment '²Ù×÷ÈËid', + PRIMARY KEY (`id`), + KEY `idx_req_id` (`req_id`), + KEY `idx_req_time` (`req_time`), + KEY `idx_biz_no` (`biz_no`) +) default charset=utf8mb4 comment='Ͷ±£Á÷³Ìʼþ±í'; + +create table `risk_insurance_bill` +( + `id` bigint(20) unsigned not null auto_increment comment 'Ö÷¼üid', + `created_at` datetime not null comment '´´½¨Ê±¼ä', + `created_by` varchar(128) not null default 'sys' comment '´´½¨ÈË', + `updated_at` datetime default null comment '¸üÐÂʱ¼ä', + `updated_by` varchar(128) not null default '' comment '¸üÐÂÈË', + `archived_at` datetime default null comment '¹éµµÊ±¼ä', + `archived_by` varchar(128) not null default '' comment '¹éµµÈË', + `archived_flag` tinyint(4) not null default '0' comment '¹éµµ±êʶ£º0=δ¹éµµ£¬1=Òѹ鵵', + `env` varchar(32) not null default '' comment '»·¾³±êʶ£¬DEV/SIT/STB/PRE/GRY/PRD', + `shadow` tinyint(4) not null default '0' comment 'Ó°×Ó±êʶλ (1 Ó°×ÓÊý¾Ý 0 ·ÇÓ°×ÓÊý¾Ý)', + `tnt_id` varchar(64) not null default '' comment '×â»§id', + `product_line_code` varchar(64) not null default '' comment '²úÆ·Ïß±àÂë', + `biz_no` varchar(64) not null default '' comment 'ÉÏÓÎÒµÎñµ¥ºÅ£»´ò°üͶ±£µ¥Á÷³Ì½ÚµãʼþÇëÇóÁ÷Ë®ºÅ£»Íâ¼ü¹ØÁªrisk_insurance_evt.req_id', + `insurance_bill_no` varchar(64) not null default '' comment 'Ͷ±£µ¥¾ÝºÅ£»Éú³É¹æÔòǰ׺£ºIBN_', + `compensatory_contract_no` varchar(64) not null default '' comment '´ú³¥ºÏÔ¼ºÅ', + `pack_date` datetime not null comment '´ò°üÈÕÆÚ', + `insurance_mode` varchar(32) not null default '' comment 'Ͷ±£Ä£Ê½,com.bestpay.ft.compensatory.core.api.contract.enums.InsuranceModeEnum', + `insurance_amount_basis` varchar(32) not null default '' comment '±£ÏÕ½ð¶î»ù×¼£¬com.bestpay.ft.compensatory.core.api.contract.enums.InsuranceAmountBasisEnum', + `insurance_cost_calculate_rule` varchar(64) not null default '' comment '±£·Ñ¼ÆËã¹æÔò,com.bestpay.ft.compensatory.core.api.contract.enums.InsuranceCostCalculateRuleEnum', + `insurance_cost_calculate_rounding_mode` varchar(32) not null default '' comment '±£·Ñ¼ÆËãÉáλģʽ£ºÈ¡Õûģʽ,com.bestpay.ft.compensatory.core.api.contract.enums.InsuranceCostCalculateRoundingModeEnum', + `pack_rule` varchar(32) not null default '' comment '´ò°ü¹æÔò£¬com.bestpay.ft.compensatory.core.api.contract.enums.PackRuleEnum', + `total_insured_subject_count` int(11) not null default 0 comment 'Ͷ±£±êµÄ×ÜÊý£»×ܽè¾ÝÊý', + `total_insurance_amount` bigint(20) not null comment '×ܱ£ÏÕ½ð¶î£¬µ¥Î»£º·Ö', + `insurance_status` varchar(32) not null default '' comment 'Ͷ±£×´Ì¬£»¼ûö¾Ù£ºcom.bestpay.ft.compensatory.core.api.insurance.enums.InsuranceStatusEnum', + `biz_trial_insurance_cost_amount` bigint(20) default null comment 'ÒµÎñÊÔËã±£·Ñ½ð¶î£»µ¥Î»£º·Ö', + `operation_trial_insurance_cost_amount` bigint(20) default null comment 'ÔËÓªÊÔËã±£·Ñ½ð¶î£»µ¥Î»£º·Ö', + `policy_no` varchar(64) not null default '' comment '±£µ¥ºÅ', + `current_flow_node_code` varchar(64) not null default '' comment 'µ±Ç°Á÷³Ì½Úµã±àÂë', + `version_no` int(11) not null default 0 comment '°æ±¾ºÅ£¬ÀÖ¹ÛËø°æ±¾ºÅ£¬update = Ô­Öµ+1£¬³õʼ»¯=0', + PRIMARY KEY (`id`), + KEY `idx_insurance_bill_no` (`insurance_bill_no`), + KEY `idx_compensatory_contract_no` (`compensatory_contract_no`), + KEY `idx_policy_no` (`policy_no`), + KEY `idx_biz_no` (`biz_no`) +) default charset=utf8mb4 comment='Ͷ±£µ¥¾Ý±í'; + +create table `risk_insurance_cmd` +( + `id` bigint(20) unsigned not null auto_increment comment 'Ö÷¼üid', + `created_at` datetime not null comment '´´½¨Ê±¼ä', + `created_by` varchar(128) not null default 'sys' comment '´´½¨ÈË', + `updated_at` datetime default null comment '¸üÐÂʱ¼ä', + `updated_by` varchar(128) not null default '' comment '¸üÐÂÈË', + `archived_at` datetime default null comment '¹éµµÊ±¼ä', + `archived_by` varchar(128) not null default '' comment '¹éµµÈË', + `archived_flag` tinyint(4) not null default '0' comment '¹éµµ±êʶ£º0=δ¹éµµ£¬1=Òѹ鵵', + `env` varchar(32) not null default '' comment '»·¾³±êʶ£¬DEV/SIT/STB/PRE/GRY/PRD', + `shadow` tinyint(4) not null default '0' comment 'Ó°×Ó±êʶλ (1 Ó°×ÓÊý¾Ý 0 ·ÇÓ°×ÓÊý¾Ý)', + `tnt_id` varchar(64) not null default '' comment '×â»§id', + `product_line_code` varchar(64) not null default '' comment '²úÆ·Ïß±àÂë', + `insurance_bill_no` varchar(64) not null default '' comment 'Ͷ±£µ¥ºÅ£»¹ØÁªrisk_insurance_bill.insurance_bill_no', + `compensatory_contract_no` varchar(64) not null default '' comment '´ú³¥ºÏÔ¼ºÅ', + `flow_node_code` varchar(64) not null default '' comment 'Á÷³Ì½Úµã±àÂë', + `cmd_no` varchar(64) not null default '' comment 'Ö¸ÁîºÅ', + `cmd_type` varchar(32) not null default '' comment 'Ö¸ÁîÀàÐÍ,com.bestpay.ft.compensatory.core.api.insurance.enums.InsuranceCmdTypeEnum', + `cmd_exec_start_time` datetime default null comment 'Ö¸ÁîÖ´ÐпªÊ¼Ê±¼ä', + `cmd_exec_end_time` datetime default null comment 'Ö¸ÁîÖ´ÐнáÊøÊ±¼ä', + `cmd_status` varchar(32) not null default '' comment 'Ö¸Áî״̬£¬com.bestpay.ft.compensatory.core.api.insurance.enums.InsuranceCmdStatusEnum', + `ext_biz_no` varchar(128) not null default '' comment 'ÍØÕ¹ÒµÎñµ¥ºÅ£»ÍⲿҵÎñµ¥ºÅ', + `fail_code` varchar(32) NOT NULL DEFAULT '' COMMENT 'ʧ°Ü±àÂë', + `fail_message` varchar(128) NOT NULL DEFAULT '' COMMENT 'ʧ°ÜÏûÏ¢', + PRIMARY KEY (`id`), + KEY `idx_cmd_no` (`cmd_no`), + KEY `idx_compensatory_contract_no` (`compensatory_contract_no`), + KEY `idx_biz_no` (`biz_no`) +) default charset=utf8mb4 comment='Ͷ±£Ö´ÐÐÖ¸Áî±í'; + +create table `risk_insurance_subject_bill` +( + `id` bigint(20) unsigned not null auto_increment comment 'Ö÷¼üid', + `created_at` datetime not null comment '´´½¨Ê±¼ä', + `created_by` varchar(128) not null default 'sys' comment '´´½¨ÈË', + `updated_at` datetime default null comment '¸üÐÂʱ¼ä', + `updated_by` varchar(128) not null default '' comment '¸üÐÂÈË', + `archived_at` datetime default null comment '¹éµµÊ±¼ä', + `archived_by` varchar(128) not null default '' comment '¹éµµÈË', + `archived_flag` tinyint(4) not null default '0' comment '¹éµµ±êʶ£º0=δ¹éµµ£¬1=Òѹ鵵', + `env` varchar(32) not null default '' comment '»·¾³±êʶ£¬DEV/SIT/STB/PRE/GRY/PRD', + `shadow` tinyint(4) not null default '0' comment 'Ó°×Ó±êʶλ (1 Ó°×ÓÊý¾Ý 0 ·ÇÓ°×ÓÊý¾Ý)', + `tnt_id` varchar(64) not null default '' comment '×â»§id', + `product_line_code` varchar(64) not null default '' comment '²úÆ·Ïß±àÂë', + `insurance_subject_bill_no` varchar(64) not null default '' comment 'Ͷ±£±êµÄµ¥¾ÝºÅ', + `insurance_bill_no` varchar(64) not null default '' comment 'Ͷ±£µ¥¾ÝºÅ£»Íâ¼ü', + `compensatory_contract_no` varchar(64) not null default '' comment '´ú³¥ºÏÔ¼ºÅ', + `fund_org_contract_no` varchar(64) not null default '' comment '×ʽð»ú¹¹ºÏÔ¼ºÅ', + `loan_no` varchar(64) not null default '' comment '½è¾ÝºÅ', + `insurance_start_season` varchar(32) not null default '' comment 'Ͷ±£¿ªÊ¼ÕËÆÚ£»¸ñʽ£ºyyyyMM', + `insurance_end_season` varchar(32) not null default '' comment 'Ͷ±£½áÊøÕËÆÚ£»¸ñʽ£ºyyyyMM', + `insurance_amount` bigint(20) not null comment '±£ÏÕ½ð¶î£»µ¥Î»£º·Ö', + `insurance_status` varchar(32) not null default '' comment 'Ͷ±£×´Ì¬£ºcom.bestpay.ft.compensatory.core.api.insurance.enums.InsuranceSubjectInsuranceStatusEnum', + `insurance_status_desc` varchar(256) not null default '' comment 'Ͷ±£×´Ì¬ÃèÊö', + `version_no` int(11) not null default 0 comment '°æ±¾ºÅ£¬ÀÖ¹ÛËø°æ±¾ºÅ£¬update = Ô­Öµ+1£¬³õʼ»¯=0', + PRIMARY KEY (`id`), + KEY `idx_insurance_subject_bill_no` (`insurance_subject_bill_no`), + KEY `idx_insurance_bill_no` (`insurance_bill_no`), + KEY `idx_loan_no` (`loan_no`) +) default charset=utf8mb4 comment='Ͷ±£±êµÄµ¥¾Ý±í'; + +create table `risk_insurance_subject_insurance_cost_info` +( + `id` bigint(20) unsigned not null auto_increment comment 'Ö÷¼üid', + `created_at` datetime not null comment '´´½¨Ê±¼ä', + `created_by` varchar(128) not null default 'sys' comment '´´½¨ÈË', + `updated_at` datetime default null comment '¸üÐÂʱ¼ä', + `updated_by` varchar(128) not null default '' comment '¸üÐÂÈË', + `archived_at` datetime default null comment '¹éµµÊ±¼ä', + `archived_by` varchar(128) not null default '' comment '¹éµµÈË', + `archived_flag` tinyint(4) not null default '0' comment '¹éµµ±êʶ£º0=δ¹éµµ£¬1=Òѹ鵵', + `env` varchar(32) not null default '' comment '»·¾³±êʶ£¬DEV/SIT/STB/PRE/GRY/PRD', + `shadow` tinyint(4) not null default '0' comment 'Ó°×Ó±êʶλ (1 Ó°×ÓÊý¾Ý 0 ·ÇÓ°×ÓÊý¾Ý)', + `tnt_id` varchar(64) not null default '' comment '×â»§id', + `product_line_code` varchar(64) not null default '' comment '²úÆ·Ïß±àÂë', + `insurance_subject_bill_no` varchar(64) not null default '' comment 'Ͷ±£±êµÄµ¥¾ÝºÅ£»Íâ¼ü', + `insurance_bill_no` varchar(64) not null default '' comment 'Ͷ±£µ¥¾ÝºÅ£»ÈßÓà', + `compensatory_contract_no` varchar(64) not null default '' comment '´ú³¥ºÏÔ¼ºÅ£»ÈßÓà', + `fund_org_contract_no` varchar(64) not null default '' comment '×ʽð»ú¹¹ºÏÔ¼ºÅ£»ÈßÓà', + `loan_no` varchar(64) not null default '' comment '½è¾ÝºÅ£»ÈßÓà', + `insurance_cost_rate` varchar(64) not null default '' comment '±£·Ñ·ÑÂÊ£»ÈßÓà', + `biz_trial_insurance_cost_amount` bigint(20) default null comment 'ÒµÎñÊÔËã±£·Ñ½ð¶î£»µ¥Î»£»·Ö', + `operation_trial_insurance_cost_amount` bigint(20) default null comment 'ÔËÓªÊÔËã±£·Ñ½ð¶î£»µ¥Î»£º·Ö', + `insurance_company_insurance_cost_amount` bigint(20) default null comment '±£Ë¾±£·Ñ½ð¶î£»µ¥Î»£º·Ö', + PRIMARY KEY (`id`), + KEY `idx_insurance_subject_bill_no` (`insurance_subject_bill_no`), + KEY `idx_insurance_bill_no` (`insurance_bill_no`), + KEY `idx_compensatory_contract_no` (`compensatory_contract_no`), + KEY `idx_loan_no` (`loan_no`) +) default charset=utf8mb4 comment='Ͷ±£±êµÄ±£·ÑÐÅÏ¢±í'; + +--- ÆÀÉóID£ºhkoz8gfwly +create table `risk_insurance_loan_notify_evt` +( + `id` bigint(20) unsigned not null auto_increment comment 'Ö÷¼üid', + `created_at` datetime not null comment '´´½¨Ê±¼ä', + `created_by` varchar(128) not null default 'sys' comment '´´½¨ÈË', + `updated_at` datetime default null comment '¸üÐÂʱ¼ä', + `updated_by` varchar(128) not null default '' comment '¸üÐÂÈË', + `archived_at` datetime default null comment '¹éµµÊ±¼ä', + `archived_by` varchar(128) not null default '' comment '¹éµµÈË', + `archived_flag` tinyint(4) not null default '0' comment '¹éµµ±êʶ£º0=δ¹éµµ£¬1=Òѹ鵵', + `env` varchar(32) not null default '' comment '»·¾³±êʶ£¬DEV/SIT/STB/PRE/GRY/PRD', + `shadow` tinyint(4) not null default '0' comment 'Ó°×Ó±êʶλ (1 Ó°×ÓÊý¾Ý 0 ·ÇÓ°×ÓÊý¾Ý)', + `tnt_id` varchar(64) not null default '' comment '×â»§id', + `product_line_code` varchar(64) not null default '' comment '²úÆ·Ïß±àÂë', + `req_time` datetime not null comment 'ÇëÇóʱ¼ä', + `req_id` varchar(64) not null default '' comment 'ÇëÇóÁ÷Ë®ºÅ', + `biz_no` varchar(64) not null default '' comment 'ÉÏÓÎÒµÎñµ¥ºÅ£»½è¾ÝºÅ', + `compensatory_contract_no` varchar(64) not null default '' comment '´ú³¥ºÏÔ¼ºÅ', + PRIMARY KEY (`id`), + KEY `idx_req_id` (`req_id`), + KEY `idx_req_time` (`req_time`), + KEY `idx_biz_no` (`biz_no`) +) default charset=utf8mb4 comment='Ͷ±£½è¾Ý֪ͨʼþ±í'; + +create table `risk_insurance_policy_bill` +( + `id` bigint(20) unsigned not null auto_increment comment 'Ö÷¼üid', + `created_at` datetime not null comment '´´½¨Ê±¼ä', + `created_by` varchar(128) not null default 'sys' comment '´´½¨ÈË', + `updated_at` datetime default null comment '¸üÐÂʱ¼ä', + `updated_by` varchar(128) not null default '' comment '¸üÐÂÈË', + `archived_at` datetime default null comment '¹éµµÊ±¼ä', + `archived_by` varchar(128) not null default '' comment '¹éµµÈË', + `archived_flag` tinyint(4) not null default '0' comment '¹éµµ±êʶ£º0=δ¹éµµ£¬1=Òѹ鵵', + `env` varchar(32) not null default '' comment '»·¾³±êʶ£¬DEV/SIT/STB/PRE/GRY/PRD', + `shadow` tinyint(4) not null default '0' comment 'Ó°×Ó±êʶλ (1 Ó°×ÓÊý¾Ý 0 ·ÇÓ°×ÓÊý¾Ý)', + `tnt_id` varchar(64) not null default '' comment '×â»§id', + `product_line_code` varchar(64) not null default '' comment '²úÆ·Ïß±àÂë', + `biz_no` varchar(64) not null default '' comment 'ÉÏÓÎÒµÎñµ¥ºÅ£»Â¼Èë±£µ¥Á÷³Ì½ÚµãʼþÇëÇóÁ÷Ë®ºÅ£»¹ØÁªrisk_insurance_evt.req_id', + `insurance_bill_no` varchar(64) not null default '' comment 'Ͷ±£µ¥¾ÝºÅ£»Íâ¼ü¹ØÁªrisk_insurance_bill.insurance_bill_no', + `policy_no` varchar(64) not null default '' comment '±£µ¥ºÅ', + `compensatory_contract_no` varchar(64) not null default '' comment '´ú³¥ºÏÔ¼ºÅ', + `insurer_org_ip_r_id` varchar(64) not null default '' comment '±£ÏÕÈË»ú¹¹iprid', + `applicant_org_ip_r_id` varchar(64) not null default '' comment 'Ͷ±£ÈË»ú¹¹iprid', + `total_insurance_amount` bigint(20) not null comment '×ܱ£ÏÕ½ð¶î£»µ¥Î»£º·Ö£»×ܹ²ÄÜÀíÅâ¶àÉÙÇ®', + `total_insurance_cost_amount` bigint(20) not null comment '×ܱ£·Ñ½ð¶î£»µ¥Î»£»·Ö£»×ܹ²Òª½»¶àÉÙÇ®', + `total_paid_insurance_cost_amount` bigint(20) default null comment '×ÜÒÑÖ§¸¶±£·Ñ½ð¶î£»µ¥Î»£º·Ö', + `total_pending_payment_insurance_cost_amount` bigint(20) default null comment '×Ü´ýÖ§¸¶±£·Ñ½ð¶î£»µ¥Î»£º·Ö', + `effective_start_date` date default null comment 'ÉúЧ¿ªÊ¼ÈÕÆÚ', + `effective_end_date` date default null comment 'ÉúЧ½áÊøÈÕÆÚ', + `version_no` int(11) not null default 0 comment '°æ±¾ºÅ£»ÀÖ¹ÛËø°æ±¾ºÅ£¬update = Ô­Öµ+1£¬³õʼ»¯=0', + PRIMARY KEY (`id`), + KEY `idx_policy_no` (`policy_no`), + KEY `idx_insurance_bill_no` (`insurance_bill_no`), + KEY `idx_biz_no` (`biz_no`) +) default charset=utf8mb4 comment='±£µ¥µ¥¾Ý±í'; + +create table `risk_insurance_file_info` +( + `id` bigint(20) unsigned not null auto_increment comment 'Ö÷¼üid', + `created_at` datetime not null comment '´´½¨Ê±¼ä', + `created_by` varchar(128) not null default 'sys' comment '´´½¨ÈË', + `updated_at` datetime default null comment '¸üÐÂʱ¼ä', + `updated_by` varchar(128) not null default '' comment '¸üÐÂÈË', + `archived_at` datetime default null comment '¹éµµÊ±¼ä', + `archived_by` varchar(128) not null default '' comment '¹éµµÈË', + `archived_flag` tinyint(4) not null default '0' comment '¹éµµ±êʶ£º0=δ¹éµµ£¬1=Òѹ鵵', + `env` varchar(32) not null default '' comment '»·¾³±êʶ£¬DEV/SIT/STB/PRE/GRY/PRD', + `shadow` tinyint(4) not null default '0' comment 'Ó°×Ó±êʶλ (1 Ó°×ÓÊý¾Ý 0 ·ÇÓ°×ÓÊý¾Ý)', + `insurance_bill_no` varchar(64) not null default '' comment 'Ͷ±£µ¥¾ÝºÅ£»Íâ¼ü¹ØÁª£ºrisk_insurance_bill', + `flow_node_code` varchar(64) not null default '' comment 'Á÷³Ì½Úµã±àÂë', + `file_type` varchar(32) not null default '' comment 'ÎļþÀàÐÍ', + `file_id` varchar(128) not null default '' comment 'ÎļþID', + PRIMARY KEY (`id`), + KEY `idx_insurance_bill_no` (`insurance_bill_no`) +) default charset=utf8mb4 comment='Ͷ±£µ¥ÎļþÐÅÏ¢±í'; \ No newline at end of file diff --git a/src/test/java/com/example/workutils/biz/aitest/AiTestPaneArchitectureTest.java b/src/test/java/com/example/workutils/biz/aitest/AiTestPaneArchitectureTest.java index 29e9fc1..8ec2ac9 100644 --- a/src/test/java/com/example/workutils/biz/aitest/AiTestPaneArchitectureTest.java +++ b/src/test/java/com/example/workutils/biz/aitest/AiTestPaneArchitectureTest.java @@ -13,6 +13,7 @@ import com.example.workutils.system.ui.FxTestSupport; import javafx.scene.Node; import javafx.scene.Parent; import javafx.scene.control.Accordion; +import javafx.scene.control.Button; import javafx.scene.control.ProgressBar; import javafx.scene.control.TabPane; import javafx.scene.control.TextField; @@ -38,11 +39,20 @@ class AiTestPaneArchitectureTest { assertEquals(null, FxTestSupport.fx(pane::getTop)); TabPane mainTabs = assertInstanceOf(TabPane.class, FxTestSupport.fx(pane::getCenter)); + assertEquals("项目与增é‡�", FxTestSupport.fx( + () -> mainTabs.getSelectionModel().getSelectedItem().getText())); assertEquals(List.of("项目与增é‡�", "工具链", "è´¨é‡�规范", "结果与å�ˆå¹¶"), FxTestSupport.fx(() -> mainTabs.getTabs().stream().map(tab -> tab.getText()).toList())); assertEquals(0, FxTestSupport.fx(() -> tabDescendants(mainTabs, Accordion.class).size())); assertEquals(2, FxTestSupport.fx( () -> tabDescendants(mainTabs, DirectoryPathSelector.class).size())); + List