gz-oarms/findings.md

746 lines
32 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# OARMS 研究与发现记录
---
## 逐模块检查结果2026-05-21
### BS-1 大屏管理 — 检查完成
**检查范围**: 10 个 Java 文件 + 2 个 SQL 文件
#### L1 接口存在性
联调指南 14 个接口全部存在,路由精确匹配。 ✅
| 接口 | 路径 | 状态 |
|------|------|------|
| POST /query | ✅ | |
| GET /detail | ✅ | |
| POST /save | ✅ | |
| POST /update | ✅ | |
| POST /remove | ✅ | |
| GET /options | ✅ | |
| GET /district/list | ✅ | |
| POST /toggle-status | ✅ | |
| GET /check-code | ✅ | |
| GET /check-address | ✅ | |
| GET /export | ✅ | |
| POST /import | ✅ | |
| GET /import-template | ✅ | |
| GET /histories | ✅ | |
#### L2 参数一致性
| # | 问题 | 严重程度 | 位置 |
|---|------|---------|------|
| 1 | `queryList(ScreenQuery query)` POST 方法缺少 `@RequestBody`,前端发 JSON body 时参数为空 | **P0** | Controller:47 |
| 2 | `save(ScreenSaveReq req)` POST 方法缺少 `@RequestBody` | **P0** | Controller:71 |
| 3 | `update(ScreenSaveReq req)` POST 方法缺少 `@RequestBody` | **P0** | Controller:83 |
| 4 | `remove(String id)` POST 方法未使用 `@RequestBody Map`id 无法从 JSON body 获取 | **P1** | Controller:95 |
| 5 | `toggleStatus(String id, Integer status)` POST 方法缺少参数绑定注解 | **P1** | Controller:144 |
> 说明:无 @RequestBody 时 Spring 从 query string / form data 绑定,前端 Axios 发 JSON body 会收不到数据。e2e 测试通过是因为测试脚本用了 query params。
#### L3 返回值一致性
| # | 问题 | 严重程度 | 位置 |
|---|------|---------|------|
| 6 | `save()` 返回 `RestResult.ok()` 未携带新建实体 ID前端无法获取新记录 ID | **P1** | ServiceImpl:93-98 |
| 7 | ScreenDetailVO 的 createTime/updateTime 使用 `Date` 类型ScreenHistoryEntity 的 changedAt 使用 `LocalDateTime`,类型不一致 | **P2** | VO:94-97, HistoryEntity:41 |
| 8 | histories 返回的 snapshotData 是 CLOB(JSON) 字符串,前端需 JSON.parse无提示 | **P2** | ServiceImpl:253 |
#### L4 DTO-DB 映射
| # | 问题 | 严重程度 | 位置 |
|---|------|---------|------|
| 9 | ScreenEntity 缺少 `@DS("master")` 注解,开发指南约定必须标注 | **P2** | ScreenEntity:23 |
| 10 | ScreenHistoryEntity 缺少 `@DS("master")` 注解 | **P2** | ScreenHistoryEntity:25 |
其余 @TableField 与 DDL 列名完全对应,类型映射正确。 ✅
#### L5 数据完整性
- DDL 文件存在 ✅
- 初始数据 8 条 ✅
- DM8 已建表 ✅
#### L6 代码规范
| # | 问题 | 严重程度 | 位置 |
|---|------|---------|------|
| 11 | Controller 全部方法缺少 `log.info("[OK] ...")` 日志 | **P3** | Controller 全文件 |
| 12 | `AssertUtils.isNotNull(entity, "大屏信息不存在")` 第二个 String 参数会被当作 varargs 的第二个对象检查,不会作为错误消息显示 | **P3** | ServiceImpl:106 |
| 13 | IScreenService 所有方法返回 RestResultService 层与 HTTP 响应格式耦合 | **P3** | IScreenService 全文件 |
| 14 | update() 中 `BeanUtils.copyProperties(req, entity)` 会用 req 中 null 字段覆盖 entity 已有值 | **P2** | ServiceImpl:107 |
#### 问题汇总
| 严重程度 | 数量 |
|---------|------|
| P0 阻塞 | 3 |
| P1 严重 | 2 |
| P2 一般 | 5 |
| P3 建议 | 3 |
| **合计** | **13** |
---
### LB-1 法律法规 — 检查完成
**检查范围**: 7 个 Java 文件 + 2 个 SQL 文件
#### L1 接口存在性
联调指南 9 个接口全部存在,路由精确匹配。 ✅
#### L2 参数一致性
| # | 问题 | 严重程度 | 位置 |
|---|------|---------|------|
| 1 | `queryList` POST 缺少 `@RequestBody`(同 BS-1 模式) | **P0** | Controller:44 |
| 2 | `save` POST 缺少 `@RequestBody` | **P0** | Controller:68 |
| 3 | `update` POST 缺少 `@RequestBody` | **P0** | Controller:80 |
| 4 | `remove(String id)` POST 缺少参数绑定 | **P1** | Controller:92 |
| 5 | `repeal(String id)` POST 缺少参数绑定 | **P1** | Controller:109 |
Query 字段与联调指南一致 ✅。SaveReq 字段与联调指南一致 ✅。
#### L3 返回值一致性
| # | 问题 | 严重程度 | 位置 |
|---|------|---------|------|
| 6 | `save()` 未返回新建实体 ID | **P1** | ServiceImpl:69-74 |
直接返回 Entity 而非 VO与联调指南定义一致 ✅。
#### L4 DTO-DB 映射
| # | 问题 | 严重程度 | 位置 |
|---|------|---------|------|
| 7 | LawClauseEntity 缺少 `@DS("master")` | **P2** | Entity:24 |
其余 @TableField 与 DDL 列名完全对应,类型映射正确 ✅。
#### L5 数据完整性
DDL ✅、初始数据 5 条 ✅、DM8 建表 ✅
#### L6 代码规范
| # | 问题 | 严重程度 | 位置 |
|---|------|---------|------|
| 8 | **`repeal()` 设置 `effectiveStatus=0`,但 DDL 定义废止应为 21=有效,2=废止)** | **P1** | ServiceImpl:121 |
| 9 | `update()` BeanUtils.copyProperties null 字段覆盖 | **P2** | ServiceImpl:83 |
| 10 | Controller 全部方法缺少 `log.info("[OK]")` | **P3** | Controller 全文件 |
| 11 | `publishDate`@JsonFormat 使用硬编码 `"yyyy-MM-dd"`,应使用 `DateUtil.DATE_DEFAULT_FORMAT` | **P3** | Entity:50, SaveReq:57 |
| 12 | `AssertUtils.isNotNull(entity, "msg")` message 参数不生效 | **P3** | ServiceImpl:82,120 |
#### 问题汇总
| 严重程度 | 数量 |
|---------|------|
| P0 阻塞 | 3 |
| P1 严重 | 3 |
| P2 一般 | 2 |
| P3 建议 | 3 |
| **合计** | **11** |
---
### MR-1 监测规则 — 检查完成
**检查范围**: 12 个 Java 文件 + 2 个 SQL 文件
#### L1 接口存在性
联调指南 11 个接口全部存在,路由精确匹配。 ✅
#### L2 参数一致性
| # | 问题 | 严重程度 | 位置 |
|---|------|---------|------|
| 1 | `queryList` POST 缺少 `@RequestBody`(同 BS-1 模式) | **P0** | Controller:44 |
| 2 | `save` POST 缺少 `@RequestBody` | **P0** | Controller:68 |
| 3 | `update` POST 缺少 `@RequestBody` | **P0** | Controller:80 |
| 4 | `remove(String id)` POST 缺少参数绑定 | **P1** | Controller:92 |
| 5 | `toggleStatus(String id, Integer status)` POST 缺少参数绑定 | **P1** | Controller:105 |
Query 字段与联调指南一致 ✅。SaveReq 字段与联调指南一致 ✅。
#### L3 返回值一致性
| # | 问题 | 严重程度 | 位置 |
|---|------|---------|------|
| 6 | `save()` 未返回新建实体 ID | **P1** | ServiceImpl:126-143 |
| 7 | `scopeDistricts` 为 CLOB(JSON) 字符串,`getEnabledRules` 直接返回 String前端需 JSON.parse | **P2** | ServiceImpl:253 |
| 8 | `queryList` 返回的 VO 中 `lawClauses`/`histories` 为 null仅 detail 填充) | **P3** | ServiceImpl:72-76 |
#### L4 DTO-DB 映射
| # | 问题 | 严重程度 | 位置 |
|---|------|---------|------|
| 9 | MonitoringRuleEntity 缺少 `@DS("master")` | **P2** | Entity:21 |
其余 @TableField 与 DDL 列名完全对应 ✅。scopeDistricts CLOB → String 映射正确 ✅。
#### L5 数据完整性
DDL ✅3 张表)、初始数据 9 条 ✅、DM8 建表 ✅
#### L6 代码规范
| # | 问题 | 严重程度 | 位置 |
|---|------|---------|------|
| 10 | 操作历史 `operator` 硬编码为 `"系统管理员"`,未从登录用户获取 | **P2** | ServiceImpl:141,172,202,227 |
| 11 | `update()` BeanUtils.copyProperties null 字段覆盖 | **P2** | ServiceImpl:159 |
| 12 | `remove()` 先删除操作历史再新增一条删除记录,产生孤儿历史数据 | **P3** | ServiceImpl:192-202 |
| 13 | `buildSnapshot()` 手动拼接 JSON 字符串,字段值含引号时会破坏 JSON 格式 | **P3** | ServiceImpl:341-354 |
| 14 | Controller 全部方法缺少 `log.info("[OK]")` | **P3** | Controller 全文件 |
| 15 | `AssertUtils.isNotNull(entity, "msg")` message 参数不生效 | **P3** | ServiceImpl:151,182,213 |
#### 问题汇总
| 严重程度 | 数量 |
|---------|------|
| P0 阻塞 | 3 |
| P1 严重 | 2 |
| P2 一般 | 4 |
| P3 建议 | 6 |
| **合计** | **15** |
---
### AM-1 录屏设置 — 检查完成
**检查范围**: 7 个 Java 文件 + 1 个 DDL 文件
#### L1 接口存在性
联调指南 7 个接口全部存在 ✅
#### L2 参数一致性
| # | 问题 | 严重程度 | 位置 |
|---|------|---------|------|
| 1 | `queryList`/`save`/`update` POST 缺少 `@RequestBody`(同前模块模式) | **P0** | Controller:44,68,80 |
| 2 | `remove(String id)` / `toggleStatus(String id, Integer status)` POST 缺少参数绑定 | **P1** | Controller:92,109 |
Query/SaveReq 字段与联调指南一致 ✅。save() 有录屏时长/频率范围校验、大屏唯一性校验、时间范围校验 ✅。
#### L3 返回值一致性
| # | 问题 | 严重程度 | 位置 |
|---|------|---------|------|
| 3 | `save()` 未返回新建实体 ID | **P1** | ServiceImpl:110 |
#### L4 DTO-DB 映射
| # | 问题 | 严重程度 | 位置 |
|---|------|---------|------|
| 4 | RecordingConfigEntity 缺少 `@DS("master")` | **P2** | Entity:21 |
#### L5 数据完整性
DDL ✅、无初始数据符合预期✅、DM8 建表 ✅
#### L6 代码规范
| # | 问题 | 严重程度 | 位置 |
|---|------|---------|------|
| 5 | `update()` BeanUtils.copyProperties null 字段覆盖 | **P2** | ServiceImpl:156 |
| 6 | Controller 缺少 `log.info("[OK]")` | **P3** | Controller 全文件 |
| 7 | `AssertUtils.isNotNull(entity, "msg")` message 不生效 | **P3** | ServiceImpl:91,119 |
#### 问题汇总: P0×1, P1×2, P2×2, P3×2 = **7**
---
### AM-2 随机录屏 — 检查完成
**检查范围**: 7 个 Java 文件 + 1 个 DDL 文件
#### L1 接口存在性
联调指南 2 个接口全部存在 ✅query + detail
#### L2 参数一致性
| # | 问题 | 严重程度 | 位置 |
|---|------|---------|------|
| 1 | `queryList` POST 缺少 `@RequestBody` | **P0** | Controller:42 |
Query 字段与联调指南一致 ✅。90 天查询范围限制已实现 ✅。
#### L3/L4/L5
- detail 返回 Map含 alerts 子列表)✅
- 跨模块查询ScreenMapper 两步关联)✅
- DDL ✅、无初始数据 ✅、DM8 ✅
- Entity 缺少 `@DS("master")`**P2**
#### L6 代码规范
| # | 问题 | 严重程度 | 位置 |
|---|------|---------|------|
| 2 | Entity 缺少 `@DS("master")` | **P2** | RecordingTaskEntity |
| 3 | Controller 缺少 `log.info("[OK]")` | **P3** | Controller 全文件 |
#### 问题汇总: P0×1, P2×1, P3×1 = **3**
---
### AM-3 广告画面监控 — 检查完成
**检查范围**: 6 个 Java 文件 + 1 个 DDL 文件
#### L1 接口存在性
联调指南 4 个接口全部存在 ✅query, detail, start, judge
#### L2 参数一致性
| # | 问题 | 严重程度 | 位置 |
|---|------|---------|------|
| 1 | `queryList` POST 缺少 `@RequestBody` | **P0** | Controller:41 |
| 2 | `judgeMonitor(MonitorJudgeReq req)` POST 缺少 `@RequestBody` | **P0** | Controller:77 |
| 3 | `startMonitor(String id)` POST 缺少参数绑定 | **P1** | Controller:65 |
Query 字段与联调指南一致 ✅。默认过滤已判定记录monitorStatus < 3)✅。
#### L3 返回值一致性
- 直接返回 Entity与联调指南一致
#### L4 DTO-DB 映射
| # | 问题 | 严重程度 | 位置 |
|---|------|---------|------|
| 4 | MonitorRecordEntity 缺少 `@DS("master")` | **P2** | Entity |
#### L5 数据完整性
DDL ✅、无初始数据 ✅、DM8
#### L6 代码规范
| # | 问题 | 严重程度 | 位置 |
|---|------|---------|------|
| 5 | `autoCreateEvidence()` try-catch 吞掉异常取证创建失败但监控判定仍成功导致数据不一致 | **P2** | ServiceImpl:148-176 |
| 6 | Controller 缺少 `log.info("[OK]")` | **P3** | Controller 全文件 |
| 7 | `AssertUtils.isNotNull` message 不生效 | **P3** | ServiceImpl:101,126 |
#### 问题汇总: P0×2, P1×1, P2×2, P3×2 = **7**
---
### CW-1 固化取证 — 检查完成
**检查范围**: 7 Java 文件 + 1 DDL 文件
#### L1 接口存在性
联调指南 5 个接口全部存在
#### L2/L3/L4/L5/L6 汇总
| # | 问题 | 严重程度 | 位置 |
|---|------|---------|------|
| 1 | `queryList`/`save` POST 缺少 `@RequestBody` | **P0** | Controller:43,67 |
| 2 | `save()` 未返回新建实体 ID | **P1** | ServiceImpl:144 |
| 3 | EvidenceRecordEntity 缺少 `@DS("master")` | **P2** | Entity:25 |
| 4 | download/play 返回占位路径TODO 对接文件存储系统 | **P2** | ServiceImpl:161,174 |
| 5 | Controller 缺少 `log.info("[OK]")` | **P3** | Controller 全文件 |
| 6 | `AssertUtils.isNotNull` message 不生效 | **P3** | ServiceImpl:132,156,168 |
DTO-DB 映射正确 ✅。@JsonFormat 使用 DateUtil 常量 ✅。@DSTransactional 正确使用 ✅。
`AssertUtils.isTrue` 正确使用 `BaseResultCode.PARAM_IS_INVALID` ✅。
#### 问题汇总: P0×1, P1×1, P2×2, P3×2 = **6**
---
### CW-2 规则关联 — 检查完成
**检查范围**: 5 Java 文件 + 1 DDL 文件
#### L1 接口存在性
联调指南 2 个接口全部存在
#### 汇总
| # | 问题 | 严重程度 | 位置 |
|---|------|---------|------|
| 1 | `relate` POST 缺少 `@RequestBody` | **P0** | Controller:53 |
| 2 | Entity 缺少 `@DS("master")` | **P2** | Entity |
| 3 | `associatedBy` 硬编码 `"系统管理员"` | **P2** | ServiceImpl:103 |
| 4 | Controller 缺少 `log.info("[OK]")` | **P3** | Controller 全文件 |
`AssertUtils.isTrue` 正确使用 `BaseResultCode` ✅。跨模块校验证据状态规则有效性完整 ✅。
#### 问题汇总: P0×1, P2×2, P3×1 = **4**
---
### CW-3 线索生成 — 检查完成
**检查范围**: 8 Java 文件 + 1 DDL 文件
#### L1 接口存在性
联调指南 5 个接口全部存在
#### L2/L3/L4/L6 汇总
| # | 问题 | 严重程度 | 位置 |
|---|------|---------|------|
| 1 | `queryList` POST 缺少 `@RequestBody` | **P0** | Controller:43 |
| 2 | `generateClue(String evidenceId)` POST 缺少参数绑定 | **P1** | Controller:67 |
| 3 | `generateClue()` 未返回新建线索 ID | **P1** | ServiceImpl:222 |
| 4 | `statusSummary()` 仅统计状态 1-2遗漏 3(处理中) 4(已办结) | **P1** | ServiceImpl:244-253 |
| 5 | `relatedRules`/`relatedLawClauses` CLOB(JSON) 字符串前端需 JSON.parse | **P2** | ServiceImpl:181,183 |
| 6 | Entity 缺少 `@DS("master")` | **P2** | Entity |
| 7 | `generatedBy` 硬编码 `"系统管理员"` | **P2** | ServiceImpl:191 |
| 8 | `aggregateRuleInfo()` N+1 查询循环内 selectById | **P2** | ServiceImpl:276-287 |
| 9 | `buildRulesJson`/`buildLawClausesJson` 手动拼 JSON字段值含引号会破坏格式 | **P3** | ServiceImpl:293-355 |
| 10 | Controller 缺少 `log.info("[OK]")` | **P3** | Controller 全文件 |
#### 问题汇总: P0×1, P1×3, P2×4, P3×2 = **10**
---
### CW-4 线索转办 — 检查完成
**检查范围**: 14 Java 文件 + 1 DDL 文件
#### L1 接口存在性
联调指南 13 个接口全部存在
#### L2/L3/L4/L6 汇总
| # | 问题 | 严重程度 | 位置 |
|---|------|---------|------|
| 1 | 6 POST 接口缺少 `@RequestBody`query/submit/pending-clues.query/status-update/urge/withdraw | **P0** | Controller:51,75,105,123,129,135 |
| 2 | `submitTransfer()` 未返回转办记录 ID | **P1** | ServiceImpl:175 |
| 3 | 2 Entity 缺少 `@DS("master")` | **P2** | Entity |
| 4 | `transferPerson` 硬编码 `"系统管理员"` | **P2** | ServiceImpl:152 |
| 5 | `departmentList`/`personList` 返回硬编码模拟数据TODO 对接组织架构 | **P2** | ServiceImpl:198-231 |
| 6 | `queryList` 列表查询存在 N+1每条记录 selectById 查线索编码 | **P2** | ServiceImpl:81-84 |
| 7 | Controller 缺少 `log.info("[OK]")` | **P3** | Controller 全文件 |
| 8 | `AssertUtils.isNotNull` message 不生效 | **P3** | ServiceImpl:139,293,335,378 |
状态流转校验完整transferredprocessingcompleted/failed)✅。撤回回退线索状态 ✅。`@DSTransactional` 正确使用 ✅。
#### 问题汇总: P0×1, P1×1, P2×5, P3×2 = **9**
---
## 全模块检查总结
| 模块 | P0 | P1 | P2 | P3 | 合计 |
|------|----|----|----|----|------|
| BS-1 大屏管理 | 3 | 2 | 5 | 3 | 13 |
| LB-1 法律法规 | 3 | 3 | 2 | 3 | 11 |
| MR-1 监测规则 | 3 | 2 | 4 | 6 | 15 |
| AM-1 录屏设置 | 1 | 2 | 2 | 2 | 7 |
| AM-2 随机录屏 | 1 | 0 | 1 | 1 | 3 |
| AM-3 广告监控 | 2 | 1 | 2 | 2 | 7 |
| CW-1 固化取证 | 1 | 1 | 2 | 2 | 6 |
| CW-2 规则关联 | 1 | 0 | 2 | 1 | 4 |
| CW-3 线索生成 | 1 | 3 | 4 | 2 | 10 |
| CW-4 线索转办 | 1 | 1 | 5 | 2 | 9 |
| **合计** | **17** | **15** | **29** | **24** | **85** |
### 跨模块共性问题(高频模式)
#### 模式 1POST 接口缺少 @RequestBodyP0影响全部模块
所有模块的 POST 接口query/save/update 均缺少 `@RequestBody` 注解前端使用 Axios 发送 JSON body 时参数全部为空
**修复方案**统一在所有 POST 接口的对象参数前添加 `@RequestBody`对于简单参数String id, Integer status使用 `@RequestBody Map<String, Object>` `@RequestParam`
#### 模式 2save() 不返回新建实体 IDP1影响 7 个模块)
所有新增接口返回 `RestResult.ok()` 而非 `RestResult.ok(entity.getId())`前端无法获取新创建记录的 ID
#### 模式 3Entity 缺少 @DS("master")P2影响全部 10 个模块)
所有 Entity 仅标注 `@TableName(schema = "OARMS")` 但缺少 `@DS("master")` master primary 数据源暂时不影响运行但不符合开发规范
#### 模式 4操作人硬编码P2影响 MR-1/CW-2/CW-3/CW-4
所有写入操作的操作人operator/generatedBy/transferPerson/associatedBy硬编码为 `"系统管理员"`未从登录用户获取
#### 模式 5手动拼接 JSON 字符串P3影响 MR-1/CW-3
`buildSnapshot`/`buildRulesJson`/`buildLawClausesJson` 使用 StringBuilder 拼接 JSON字段值含特殊字符时会破坏格式应使用 JSON 库序列化
#### 模式 6Controller 缺少日志P3影响全部模块
所有 Controller 方法未按规范输出 `log.info("[OK] ...")` 日志
#### 模式 7BeanUtils.copyProperties null 覆盖P2影响 5 个模块)
update 方法中 `BeanUtils.copyProperties(req, entity)` 会用 req 中的 null 字段覆盖 entity 的已有值
---
## 代码结构发现
### 模块对应关系(计划 vs 实际)
| 计划阶段 | 计划模块 | SQL DDL | SQL 初始数据 | Java 代码层 | 状态 |
|----------|----------|---------|-------------|-------------|------|
| Phase 1 | BS-1 大屏基础信息管理 | V1.0.0__BS_screen_ddl.sql | V1.0.0__BS_screen_init_data.sql | screen (Entity/Query/Req/VO/Mapper/Service/Controller) | 完成 |
| Phase 2 | LB-1 法律法规管理 | V2.0.0__LB_law_ddl.sql | V2.0.0__LB_law_init_data.sql | law (Entity/Query/Req/Mapper/Service/Controller) | 完成 |
| Phase 3 | MR-1 监测规则管理 | V6.0.0__MR_monitoring_rule_ddl.sql | V6.0.0__MR_monitoring_rule_init_data.sql | rule (Entity×3/Query/Req/VO/Mapper×3/Service/Controller) | 完成 |
| Phase 4 | AM-1 录屏设置管理 | V3.0.0__AM_recording_config_ddl.sql | 无初始数据 | monitor.config (Entity/Query/Req/Mapper/Service/Controller) | 完成 |
| Phase 5 | AM-2 随机录屏 | V4.0.0__AM_recording_task_ddl.sql | 无初始数据 | monitor.task (Entity×2/Query/Mapper×2/Service/Controller) | 完成 |
| Phase 6 | AM-3 广告画面监控 | V5.0.0__AM_monitor_record_ddl.sql | 无初始数据 | monitor.record (Entity/Query/Req/Mapper/Service/Controller) | 完成 |
| Phase 7 | CW-1 固化取证 | V7.0.0__CW_evidence_ddl.sql | 无初始数据 | evidence.record (Entity×2/Query/Req/VO/Mapper×2/Service/Controller) | 完成 |
| Phase 8 | CW-2 规则关联 | V8.0.0__CW_evidence_rule_relation_ddl.sql | 无初始数据 | evidence.relation (Entity/Query/Req/Mapper/Service/Controller) | 完成 |
| Phase 9 | CW-3 线索生成 | V9.0.0__CW_monitoring_clue_ddl.sql | 无初始数据 | evidence.clue (Entity×2/Query/VO/Mapper×2/Service/Controller) | 完成 |
| Phase 10 | CW-4 线索转办 | V10.0.0__CW_clue_transfer_ddl.sql | 无初始数据 | evidence.transfer (Entity×2/Query/Req/VO/Mapper×2/Service/Controller) | 完成 |
### 关键发现
1. **SQL 版本号与计划阶段不一致**: SQL 文件版本号 (V1~V10) 与计划阶段 (Phase 1~10) 顺序不同MR-1 监测规则在计划中是 Phase 3 SQL 编号为 V6这不影响功能但说明 SQL 文件是按模块类别分组而非按依赖顺序编号
2. **无 Mapper XML 文件**: 所有模块使用 MyBatis-Plus 注解方式没有 XML mapper 文件这是正常的
3. **初始数据**: BS-1LB-1MR-1 有初始数据 SQL其余模块无需预置数据合理)。
4. **编译状态**: 代码已通过 git commit `c06a4e5` 提交commit 信息为 "feat: OARMS 全模块后端代码 + DM8 数据库适配"。
### 技术栈确认
- 框架: Spring Boot + MyBatis-Plus
- 数据库: DM8达梦数据库版本 `--03134283914-20220901-168571-20009`
- 权限: Sa-TokenStpInterfaceImpl 存在
- 项目结构: modules/{模块}/{子模块}/{layer}
### 数据源架构决策2026-05-18
项目配置了两个数据源共用同一 DM8 实例 `172.22.80.70:15236`
| 数据源名 | Schema | 用途 | 决策 |
|----------|--------|------|------|
| `master` | OARMS | 业务数据全部 17 张业务表 | 保留 |
| `youfool` | YOUFOOL | 框架 restLog接口访问日志`RestLogServiceImpl` 硬编码 `@DS("youfool")` | 保留 |
**决策**: 保持现状不合并框架代码不可修改youfool 数据源是框架层强制依赖
### PRD vs 后端代码覆盖分析2026-05-18
#### 比对方法
读取每个模块的 `S4-API设计.md`逐条对照后端 Controller 中实际定义的接口
#### 整体结论
- **10 个模块全部有基础 CRUD 后端代码**Entity/Mapper/Service/Controller
- **路径命名风格不一致**后端统一用单数名词`/api/screen`PRD 用复数`/api/screens`
- **HTTP 方法不一致**后端几乎全用 POSTPRD 规范使用 RESTful 风格PUT/DELETE
- **高级功能接口大量缺失**
#### 逐模块覆盖详情
##### BS-1 大屏基础信息管理
| PRD 接口 | 功能 | 后端状态 |
|----------|------|---------|
| POST /api/screens/query | 列表查询 | |
| POST /api/screens | 新增 | (路径 /api/screen/save) |
| PUT /api/screens/{id} | 编辑 | (路径 /api/screen/update) |
| GET /api/screens/{id} | 详情 | (路径 /api/screen/detail) |
| DELETE /api/screens/{id} | 删除 | (路径 /api/screen/remove) |
| PUT /api/screens/{id}/status | 状态变更 | 未实现 |
| GET /api/screens/export | 导出 | 未实现 |
| POST /api/screens/import | 批量导入 | 未实现 |
| GET /api/screens/import-template | 下载导入模板 | 未实现 |
| GET /api/screens/{id}/histories | 历史版本列表 | 未实现 |
| GET /api/screens/check-code | 编码唯一校验 | 未实现 |
| GET /api/screens/check-address | 地址唯一校验 | 未实现 |
##### LB-1 法律法规管理
| PRD 接口 | 功能 | 后端状态 |
|----------|------|---------|
| POST /api/law-clauses/query | 列表查询 | |
| POST /api/law-clauses | 新增 | (路径 /api/law-clause/save) |
| PUT /api/law-clauses/{id} | 编辑 | (路径 /api/law-clause/update) |
| GET /api/law-clauses/{id} | 详情 | (路径 /api/law-clause/detail) |
| DELETE /api/law-clauses/{id} | 删除 | (路径 /api/law-clause/remove) |
| PUT /api/law-clauses/{id}/repeal | 废止条款 | 未实现 |
| GET /api/law-clauses/check-clause-number | 条款号唯一校验 | 未实现 |
| GET /api/law-clauses/effective | 已生效条款列表 | 未实现 |
##### MR-1 监测规则管理
| PRD 接口 | 功能 | 后端状态 |
|----------|------|---------|
| POST /api/monitoring-rules/query | 列表查询 | |
| POST /api/monitoring-rules | 新增 | |
| PUT /api/monitoring-rules/{id} | 编辑 | (POST /update) |
| GET /api/monitoring-rules/{id} | 详情 | (GET /detail) |
| DELETE /api/monitoring-rules/{id} | 删除 | (POST /remove) |
| PUT /api/monitoring-rules/{id}/toggle-status | 切换启用状态 | (POST /toggle-status) |
| GET /api/monitoring-rules/check-name | 名称唯一校验 | |
| GET /api/monitoring-rules/enabled | 已启用规则列表 | |
| GET /api/monitoring-rules/{id}/histories | 操作历史 | 未实现详情接口已含历史 |
| POST /api/monitoring-rules/export | 导出Excel | 未实现 |
##### AM-1 录屏设置管理
| PRD 接口 | 功能 | 后端状态 |
|----------|------|---------|
| POST /api/recording-configs/query | 列表查询 | |
| POST /api/recording-configs | 新增 | |
| PUT /api/recording-configs/{id} | 编辑 | (POST /update) |
| GET /api/recording-configs/{id} | 详情 | |
| PUT /api/recording-configs/{id}/status | 状态变更 | 未实现 |
| GET /api/screens/available | 可配置大屏列表 | (路径不同) |
##### AM-2 随机录屏
| PRD 接口 | 功能 | 后端状态 |
|----------|------|---------|
| POST /api/recording-tasks/query | 列表查询 | |
| GET /api/recording-tasks/{id} | 详情 | |
##### AM-3 广告画面监控
| PRD 接口 | 功能 | 后端状态 |
|----------|------|---------|
| POST /api/monitor-records/query | 列表查询 | |
| GET /api/monitor-records/{id} | 详情 | |
| PUT /api/monitor-records/{id}/start | 开始监控 | |
| PUT /api/monitor-records/{id}/judge | 监控判定 | |
##### CW-1 固化取证
| PRD 接口 | 功能 | 后端状态 |
|----------|------|---------|
| POST /api/evidence-records/query | 列表查询 | |
| GET /api/evidence-records/{id} | 详情 | |
| POST /api/evidence-records | 保存取证 | |
| GET /api/evidence-records/{id}/status-history | 状态历史 | 未实现详情接口已含 |
| GET /api/evidence-records/{id}/download | 下载地址 | 未实现 |
| GET /api/evidence-records/{id}/play | 播放地址 | 未实现 |
##### CW-2 规则关联
| PRD 接口 | 功能 | 后端状态 |
|----------|------|---------|
| GET /api/evidence-rule-relations | 查询已关联规则 | |
| POST /api/evidence-rule-relations | 关联规则 | |
##### CW-3 线索生成
| PRD 接口 | 功能 | 后端状态 |
|----------|------|---------|
| POST /api/monitoring-clues/query | 列表查询 | |
| GET /api/monitoring-clues/{id} | 详情 | |
| POST /api/monitoring-clues | 生成线索 | |
| GET /api/evidence-records/{id}/clue-preview | 线索预览 | 未实现 |
| GET /api/monitoring-clues/status-summary | 状态统计 | 未实现 |
##### CW-4 线索转办
| PRD 接口 | 功能 | 后端状态 |
|----------|------|---------|
| POST /api/clue-transfer/query | 转办记录列表 | |
| GET /api/clue-transfer/{id} | 转办详情 | |
| POST /api/clue-transfer/submit | 提交转办 | |
| GET /api/clue-transfer/districts | 区域列表 | 未实现 |
| GET /api/clue-transfer/districts/{code}/departments | 部门列表 | 未实现 |
| GET /api/clue-transfer/departments/{id}/persons | 人员列表 | 未实现 |
| GET /api/clue-transfer/clues/{id}/disposal-feedback | 处置反馈 | 未实现 |
#### 缺失接口汇总
> 注:下表中标记 ❌ 的接口已在 2026-05-18 的"缺失接口补齐"和"CW-4 完善"中全部实现。此表保留作为历史对照。
| 类别 | 原缺失数 | 当前状态 |
|------|---------|---------|
| 导入/导出/模板下载 | 3 | 已补齐 |
| 唯一性校验 | 2 | 已补齐 |
| 状态变更/废止 | 2 | 已补齐 |
| 历史版本 | 1 | 已补齐 |
| 文件下载/播放 | 2 | 已补齐 |
| 级联选择 | 3 | 已补齐 |
| 线索预览/统计 | 2 | 已补齐 |
| 处置反馈 | 1 | 已补齐 |
| CW-4 业务闭环 | 6 | 已补齐pending-clues/status-update/urge/withdraw/operation-logs |
---
### PRD vs 后端代码详细差异分析2026-05-18 更新)
> 基础 CRUD 和 P0-P3 补齐接口均已实现并通过端到端测试。以下仅列出**仍然存在的差异**。
#### 一、风格差异(不影响功能)
| 项目 | PRD 要求 | 后端实现 | 影响 |
|------|---------|---------|------|
| 路径命名 | 复数名词 `/api/screens` | 单数名词 `/api/screen` | 不影响 |
| HTTP 方法 | RESTfulPUT/DELETE | 统一 POST | 不影响 |
| 状态枚举值 | 字符串 "RECORDING"/"COMPLETED" | 数字 1/2/3 | 不影响 |
| 分页默认大小 | 20 / | 10 / | 不影响 |
| API 前缀 | 部分 PRD 要求 `/api/cw/` | `/cw/` 前缀 | 不影响 |
#### 二、缺失的业务逻辑(需补充)
##### AM-1 录屏设置
- **唯一性校验**PRD 要求同一大屏只能有一条配置后端未在 save/update 中校验
- **时间范围校验**PRD 要求录屏时间必须在广告播放时间段内后端未实现
##### AM-2 随机录屏
- **查询条件缺失**缺少 `district`区域 `screenName`大屏名称模糊匹配筛选条件
- **时间范围限制**PRD 要求最大查询范围不超过 90 后端未限制
##### AM-3 广告画面监控
- **查询条件缺失**缺少时间范围start_time/end_time)、监控人员monitor_person筛选
- **默认状态过滤**PRD 要求默认只查询未归档记录后端未实现
- **并发控制**PRD 要求同一记录只能由一人监控后端未实现
- **自动联动**PRD 要求判定为违法时自动触发 CW-1 取证流程后端未实现
##### CW-1 固化取证
- **状态历史独立接口**PRD 要求 `GET /evidence-records/{id}/status-history`当前详情接口已含但无独立入口
- **关联上下文接口**PRD 要求 `GET /monitor-records/{id}/evidence-context`来源监控记录关联信息后端未实现
##### CW-2 规则关联
- **搜索可关联规则**PRD 要求搜索可关联的监测规则列表当前只能在 MR-1 enabled 接口获取
##### CW-3 线索生成
- **线索生成日志**PRD 要求 `GET /monitoring-clues/{id}/generation-logs`后端未实现独立接口
- **广告主补充**PRD 要求线索确认时可补充广告主信息后端 generate 接口未支持
#### 三、缺失的通用功能
| 功能 | 涉及模块 | 说明 |
|------|---------|------|
| 权限控制 | 全部 | PRD 定义了市局/区局角色数据范围过滤后端未实现 |
| 关联对象返回 | AM-1/2/3, CW-1 | PRD 要求返回 screen_info/config_info/video_info 嵌套对象后端返回平铺字段 |
| 状态中文名 | 全部 | PRD 要求返回 `xxx_text` 中文字段 task_status_text后端未实现 |
| 归档标志 | AM-3 | PRD 要求 archive_flag 字段区分已归档/未归档后端无此字段 |
#### 四、CW-4 已超出 PRD 的实现
以下接口为后端主动扩展PRD 中未要求但已实现
| 接口 | 说明 |
|------|------|
| POST /api/clue-transfer/status-update | 外部系统回调状态流转 |
| POST /api/clue-transfer/urge | 催办 |
| POST /api/clue-transfer/withdraw | 撤回 |
| GET /api/clue-transfer/pending-clues/query | 待转办线索列表 |
| GET /api/clue-transfer/pending-clues/detail | 待转办线索详情 |
| GET /api/clue-transfer/operation-logs | 操作日志独立查询 |
### 框架 API 发现2026-05-18 编译修复过程中)
#### SuperEntity框架基类
- **位置**: `com.chinaweal.youfool.framework.springboot.mybatis.plus.SuperEntity`
- **不是泛型类**直接 `extends SuperEntity` 即可
- 提供字段: `createBy`, `createTime`, `updateBy`, `updateTime`, `createName`, `updateName`
- 自动填充策略: INSERT 时填充 createBy/createTime, INSERT_UPDATE 时填充 updateBy/updateTime
#### AssertUtils断言工具
- **位置**: `com.chinaweal.youfool.framework.springboot.common.util.AssertUtils`
- `isTrue(boolean, ResultCode, Object... params)` 第二个参数是 ResultCode 枚举不是 String
- `isNotNull(Object...)` 无消息参数版本使用 BaseResultCode.PARAM_NOT_COMPLETE
- `isNotBlank(String...)` 无消息参数版本使用 BaseResultCode.PARAM_IS_BLANK
- `isNotBlank(String, String)` 带消息参数的重载varargs 导致编译通过
#### RestResult统一返回
- **位置**: `com.chinaweal.youfool.framework.springboot.rest.RestResult`
- `ok()` / `ok(T data)` 成功返回
- `error(ResultCode)` / `error(ResultCode, String msg)` / `error(ResultCode, T data)` 错误返回
- **没有 `fail()` 方法**统一使用 `error()`
#### BaseResultCode常用错误码
- `SUCCESS` 成功
- `PARAM_IS_INVALID` 参数无效
- `PARAM_NOT_COMPLETE` 参数不完整
- `PARAM_IS_BLANK` 参数为空