2026-06-17-M3-微服务改造子计划.md 29 KB

M3 · 微服务改造实现子计划(删选层打分链 + 保留抠图链 + 消 NPE + calPhotoPosition 改本地)

编写日期:2026-06-17 · 编写员:实现计划编写员(Claude Opus 4.8) 权威输入:项目文档/需求文档/04-微服务改造方案.md项目文档/进度/文档源码审核报告.md项目文档/00-需求总览.md §5 D3/D4/D5/D10 所有文件:行号已用 codegraph MCP(codegraph_explore / codegraph_node)核对,符号真实存在、行号吻合(误差 0–2 行)。 本文档只产出计划,不改任何源码


Goal

加入机旁本地自动对焦(autofocustool 的 Tenengrad÷mean 四步标定,由 M2 在机旁直接算出最清晰层)后,删除微服务里"云端 OpenCV 打分→选最清晰层→回传对焦位置"这条选层打分链;同时保留与之同名但独立的抠图/clearest 链(CCD 正式拍照图的抠图、水印、视频合成、AI 识别)。删除打分后 t_picture.image_score 列对 AUTOFOCUS 行停写(变 null),必须同步修掉所有读取该字段的下游消费点(否则患者详情/对焦预览 NPE 崩溃);calPhotoPosition 按 D5 方案 A 保留接口、改输入源为本地对焦结果。

Architecture(受影响微服务与角色)

微服务 角色 本轮动作
aivfo-data-transmission 打分生产者 + 抠图 ★删打分链(focusPointUpdate / pictureScore / cutAutofocus / AutofocusFeign);保留 cutCCD 抠图、视频合成、AI 转发;改 2 处 orderByDesc 排序键
aivfo-business-manage 打分消费者 ★★改三处 image_score 消费(消 NPE + 换判据)
aivof-tl-control 对焦位置编排 改 calPhotoPosition 输入源(D5-A);删 AutofocusApiController/AutofocusApi/AutofocusUpdateEvent(Handle) 入云端打分回传的部分
aivfo-ai-middleware / aivfo-gateway / aivfo-service 不受影响 仅 M3-04 回归确认
ivf_tl_control_2.0(C# 机旁端) native 本地打分 M3-01b 只做评估 + 登记 V-007,C# 改动归 M2/合并端,本计划不改

Tech Stack

Java 8 · Spring Boot 微服务集群(Feign / Kafka / MyBatis-Plus 分表)· JNA→opencv_world*.dll(打分/抠图 native)· t_picture 动态分表。

范围与约束(⚠️ 必读)

  • 本地无法构建/运行:开发机仅 java 8,无 mvn 编译验证、无运行中的微服务/DB/Kafka。
  • 因此每个任务不写 mvn 命令、不假装本地能跑。每步完成后只做:①代码完成 → ②登记"待验证清单"(标注依赖 SpringBoot 工具链 / 微服务集群 / 数据库)→ ③留待 M7 集中测
  • 本计划不改 C# 源码(ivf_tl_control_2.0),只做去留评估并交叉引用 M2/合并端。
  • 删除顺序铁律:先删消费者/引用方,再删生产者/被引用方,避免编译期残留引用(详见各任务"删除顺序"小节)。

⚠️ 两条同名独立链路(致命陷阱)

链路 处理对象 clearest 来源 本轮
① 选层打分链 PhotoMode.AUTOFOCUS 一 well 多层对焦图 微服务 OpenCV 打分 image_score
② 抠图/clearest 链 PhotoMode.CCD 正式拍照图 下位机直接标记 ImageDTO.clearestDegreeOfClarity),非微服务打分 保留

误删 ② 的后果:前端展示、AI 识别、getClearest/getClearestByDevelopTimegetPicturesByEmbryoId(eq PhotoMode.CCD) 全废 → 患者看不到图、AI 不识别。删任何代码前先确认 PhotoMode:碰 AUTOFOCUS 才删,碰 CCD/DegreeOfClarity.CLEAREST 一律保留。

⚠️ 同名类歧义

PictureManage.java 存在两份,只改 data-transmission 的,绝不可碰 AI 侧

  • 删 cutAutofocus 的目标:aivfo-data-transmission/aivfo-data-transmission-manage/src/main/java/com/aivfo/data/transmission/manage/image/PictureManage.java
  • 不可误改:aivfo-ai-middleware/aivfo-ai-middleware-manage/src/main/java/com/aivfo/ai/middleware/manage/PictureManage.java(AI 侧 interface,与打分无关)

M3-01 · 删选层打分链(data-transmission + tl-control 生产/编排侧)

目标:删除 ① 选层打分链的全部专属代码。严格按删除顺序:消费者/引用方先删,生产者/被引用类后删。

删除顺序(编译依赖拓扑,自上而下执行)

步骤1  ImageReceiveCompleteEventHandle: 删 case AUTOFOCUS 分支 + focusPointUpdate 方法 + autofocusFeign 字段 + import
   ↓(focusPointUpdate 删后,AutofocusFeign / CalAutoFocusDTO 失去唯一/全部调用方)
步骤2  AutofocusFeign 整类删(连带 CLOUD_SERVER_FOCUS_ALARM 该处引用)
   ↓(AutofocusFeign 删后,tl-control 的 AutofocusApi Feign 失去唯一远程调用方)
步骤3  cutAutofocus 私有方法删 + cropPicture 两个重载的 AUTOFOCUS else 分支改(见 4.1 备注)
   ↓(cutAutofocus 删后,PictureProcessing.pictureScore + Picture.getscore 失去唯一调用方)
步骤4  PictureProcessing(Impl).pictureScore + Picture.getscore native 绑定删
   ↓(D5-A 范围,与 M3-03 衔接)
步骤5  tl-control: AutofocusApiController / AutofocusApi / CalAutoFocusPositionParamDTO / AutofocusUpdateEvent(Handle) 入云端回传部分按 M3-03 处理(保留 calPhotoPosition 本体)

步骤 1 — 删 imageDataHandle 的 case AUTOFOCUS + focusPointUpdate 方法

  • 文件aivfo-data-transmission/aivfo-data-transmission-manage/src/main/java/com/aivfo/data/transmission/manage/event/ImageReceiveCompleteEventHandle.java
  • 删什么
    • :72-78 imageDataHandle 中的 case AUTOFOCUS: 整段(含 this.focusPointUpdate(imageBaseDataDTO);)。删后 switch 只剩 case CCD(视频合成)+ default
    • :120-149 private void focusPointUpdate(ImageBaseDataDTO imageBaseDataDTO) 整个方法(核心选层就在 :143 stream().max(Comparator.comparing(PictureDAO::getImageScore)).get():144 setClearPosition(max.getShootingPosition()))。
    • :40 字段 final AutofocusFeign autofocusFeign;(删 focusPointUpdate 后无引用)。
    • :5 import ...entity.dto.CalAutoFocusDTO;:8 import ...rpc.feign.server.AutofocusFeign;:24 import java.util.Comparator;(删后若无其它使用则一并清,避免 unused import 告警)。
  • 为何:focusPointUpdate 是 ① 链在 data-transmission 侧的唯一编排入口;选最高分→取位置两行(:143-144)是选层打分的核心动作,本地对焦后由机旁直接产出最清晰位置,不再需要。
  • 下游受影响:删后 pictureService.getAutofocusPictureByEmbryoIdAndBatchNumber(PictureDAOServiceImpl:263)在本链不再被调用(仍是 public service 方法,其内部 :270 orderByDesc 由 M3-02 处理);autofocusFeign.calAutoFocusDTO 调用点消失,使步骤 2 可安全删 AutofocusFeign。
  • 连锁编译错误:删字段 autofocusFeign 后,@RequiredArgsConstructor 生成的构造器自动少一参,无残留引用——安全。
  • 登记待验证:V-001(依赖微服务集群+Kafka:AUTOFOCUS 图到达时不再触发对焦回传,仅落库;CCD 图视频合成不受影响)。

步骤 2 — 删 AutofocusFeign 整类

  • 文件aivfo-data-transmission/aivfo-data-transmission-rpc/src/main/java/com/aivfo/data/transmission/rpc/feign/server/AutofocusFeign.java
  • 删什么:整类 :1-66。codegraph 确认其 2 个调用点全部在 ImageReceiveCompleteEventHandle(步骤 1 已删),删后无其它引用。
  • 连带删除:55 AlarmTypeKeyEnums.CLOUD_SERVER_FOCUS_ALARM.getValue()("触发自动对焦失败云服务器报警")随该类删除而消失——这是打分链回传失败告警,与下位机定位失败告警 FocusAlarmHandler 无关,不要去动后者。
  • 为何:AutofocusFeign 唯一职责是把 CalAutoFocusDTO 经 Feign 转给 tl-control 的 AutofocusApi,是 ① 链的跨服务桥,本地化后无意义。
  • 下游受影响:tl-control 的 AutofocusApi(Feign 接口)失去唯一远程调用方 → 步骤 5 / M3-03 可删 AutofocusApiController。AlarmReportFeign.reportAlarmToCloud 仍被抠图告警等多处使用,保留不动
  • 登记待验证:V-002(依赖微服务集群:tl-control 不再收到 calAutofocusPosition 远程调用,无 404/Feign 报错;启动无该 bean 缺失报错)。

步骤 3 — 删 cutAutofocus + 改 cropPicture 的 AUTOFOCUS 分支

  • 文件aivfo-data-transmission/aivfo-data-transmission-manage/src/main/java/com/aivfo/data/transmission/manage/image/PictureManage.java(⚠️ data-transmission 侧,非 AI 侧)
  • 删什么:331-355 private CropPictureInfo cutAutofocus(...) 整个方法(其 :336pictureProcessing.pictureScore(...) 即打分入口)。
  • 改什么(cutAutofocus 的 2 个调用点,均在 cropPicture 重载的 else 分支):
    • cropPicture(image, client, cropPicture, savePicture) 重载 :244-247 else 分支当前为 cut = this.cutAutofocus(...)(注释"开始图片打分")。
    • 另一重载 cropPicture(tlSn, houseSn, ...)(04 §4.2 标注 :174-182)的对应 AUTOFOCUS 分支同理。
    • 改法(D4:AUTOFOCUS 图是否仍抠图/上传/落库的决策):04 §4.2 留为开放项。本计划建议保守做法——AUTOFOCUS 图不再打分,但仍按现有流程落库(保留对焦预览原图来源),else 分支改为返回"未打分占位":将 cut = this.cutAutofocus(...) 改为 cut = BeanUtils.clone(defaultPicture); cut.setSucceed(CropState.NOT_OPERATED.getValue());(即与 :217-223 CROPPING_SKIP 同形态,score 字段不再写入)。这样下游 buildUpdateDao 仍能落库,image_score 自然为 null(由 M3-02 兜底)。
    • ⚠️ 最终是否改为完全不落库 AUTOFOCUS 图,取决于 M3-02/D10 对焦预览的去留结论——登记为 D4 待拍板,先按"保留落库、停止打分"实现。
  • 为何:cutAutofocus 是打分在抠图入口的唯一触点;保留 cutCCD(:273-313,走 pictureProcessing.pictureCropping 抠图加水印)原样不动。
  • 下游受影响PictureProcessing.pictureScore 失去唯一调用方(cutAutofocus)→ 步骤 4 可删。cutCCDpictureCroppingcreateErrorImg 不受影响(② 链)。
  • 连锁编译错误:删 cutAutofocus 后若 cropPicture else 分支仍 =this.cutAutofocus(...) 会编译失败,必须同一提交内改掉两处 else 分支
  • 登记待验证:V-003(依赖微服务集群+DFS:AUTOFOCUS 图走 else 分支返回 NOT_OPERATED,落库 image_score=null,不报错;CCD 抠图水印像素级回归无差异)。

步骤 4 — 删 pictureScore + native getscore 绑定

  • 文件1aivfo-framework/module/aivfo-jna-spring-boot/aivfo-jna-spring-boot-core/src/main/java/com/aivfo/jna/picture/PictureProcessing.java
    • :52 接口方法 CropPictureInfo pictureScore(...)
  • 文件2aivfo-framework/module/aivfo-jna-spring-boot/aivfo-jna-spring-boot-core/src/main/java/com/aivfo/jna/picture/PictureProcessingImpl.java
    • :90-104 @Override pictureScore(...)(其 :96 picture.getscore(...) 是 JNA→opencv 打分 native 调用)。
  • 文件3aivfo-framework/module/aivfo-jna-spring-boot/aivfo-jna-spring-boot-core/src/main/java/com/aivfo/jna/picture/Picture.java
    • :46 native 声明 CropPictureInfoC getscore(...)
  • 为何:getscore 是 OpenCV 清晰度打分的 native 绑定,本地对焦后整个 java 侧打分链废弃。findcircles(抠图 :30)、createErrorImg(:59)保留——② 链仍用。
  • 下游受影响:codegraph 显示 pictureScore 唯一调用方是 cutAutofocus(步骤 3 已删),getscore 唯一调用方是 pictureScore——拓扑闭合,删除安全。注意 aivfo-jna-spring-boot-starter 下有测试 JnaApplication.java 引用 PictureProcessing,核查其是否调 pictureScore/getscore,若是则一并清理测试调用(登记 V-004)。
  • 连锁编译错误:先删 cutAutofocus(步骤3)再删此处,否则 cutAutofocus 内 pictureScore 调用悬空。
  • 登记待验证:V-004(依赖 SpringBoot 工具链:jna 模块编译通过、PictureProcessingImpl 不再加载 getscore 符号;JnaApplication 测试若引用需同步清理)。

步骤 5 — tl-control 入云端回传部分(与 M3-03 协同)

本步只标范围,实际改法见 M3-03(保留 calPhotoPosition 本体、按 D5-A 改输入源)。AutofocusApiController/AutofocusApi/AutofocusUpdateEvent(Handle) 的去留取决于"本地对焦结果怎样进入 calPhotoPosition",故合并到 M3-03 一并决策,避免割裂。


M3-01b · 机旁 C# native 打分去留评估(审核新增,只评估不改 C#)

来源:审核报告维度③第 12 项 / 遗漏项 2。04 文档把打分全归云端,遗漏机旁 C# 自带 native 打分

  • 对象ivf_tl_control_2.0 客户端
    • HouseBin.cs:2446 GetImageScoreAndSaveImage(调 native 打分并存图)
    • AivfoHelper.cs:35(P/Invoke native 打分入口)
    • picture.cs:150 image_score 字段
  • 本任务范围仅在计划里写明评估方法 + 若删的回归点,不在此 Java 计划改 C#。C# 改动归 M2/合并端,本处为交叉引用。
  • 评估方法
    1. 确认 GetImageScoreAndSaveImage 调用的 native 与云端 data-transmission 的 getscore(opencv_world*.dll) 是否同源/同 dll(比对 dll 名、导出符号、入参签名)。
    2. HouseBin.cs:2446 的上游触发:是否在"对焦拍图"流程中被调用、其输出(image_score)是否仍被机旁端用于选层或仅存档。
    3. 判定:本地 Tenengrad÷mean 标定(M2)接管选层后,这套 C# 评分若仅服务于旧的"打分选层"则可删;若另有用途(如存档展示)则保留并标注。
  • 若删的回归点:拍照流程不调用 GetImageScoreAndSaveImage 后,对焦/拍照时序是否仍完整;picture.cs image_score 字段停写对机旁本地存储/上报是否有影响。
  • 登记待验证V-007(依赖机旁真机+C# 工程,归 M2/合并端:C# native 打分与云端 getscore 是否同源、是否随本地对焦一并废弃)。

M3-02 · 消 NPE + 改判据(business-manage 三处 + data-transmission 两处排序键)

image_score 删后对 AUTOFOCUS 行全 null。业务消费点必须改判据,否则一打开患者详情/对焦预览即 NPE 崩溃。 生产侧(停写):ReceivePictureCroppingMessage.java:226/229(buildUpdateDao setImageScore(getScore()))与 ReceivePictureMessageInfo.java:179savePicture.setImageScore(cropPictureInfo.getScore()))随 M3-01 步骤 3 后 score 恒为占位值/null——这两处生产语句可保留(写 null 不报错),无需强删;列 t_picture.image_score 保留停写。

改点 1(NPE 点1)— getAutofocusPictures 选最高分

  • 文件aivfo-business-manage/.../service/impl/ResourceServiceImpl.java
  • 位置:方法 :462-481
    • :470 t.setImageName(StringUtils.format("{}_{}_{}_{}", getHouseSn(), getWellSn(), getShootingPosition(), s.getImageScore())) —— imageScore 为 null 时名字拼成 ..._null
    • :476 copy.stream().max(Comparator.comparing(A -> A.getImageScore())).get().setHighestScore(true) —— null 键 compareTo 抛 NPE;空流 .get() 抛 NoSuchElement。一点开对焦预览就崩。
  • 改法
    • :470:去掉文件名末段的 getImageScore(),改为 "{}_{}_{}" 只拼 houseSn/wellSn/shootingPosition(或追加 image_time),不再带分数。
    • :476:删除"选最高分→setHighestScore(true)"逻辑。换判据为 ② 体系的 clearest/居中层——例如对 CropState.SUCCEEDDegreeOfClarity.CLEAREST 的项设 highestScore,或取 pictureLayer==0(居中层);若无明确清晰标记则不高亮(highestScore 全 false),避免 NPE。最小实现:用 Optional 包裹并对空/ null 做兜底(filter(x->x.getImageScore()!=null)findFirst),无则跳过。
  • 为何:本地化后 AUTOFOCUS 图无打分,"最高分高亮"失去数据源;改判据后预览仍能展示一组对焦层原图(图/层/time 不依赖打分)。
  • 下游受影响FocusPreviewPictureVO.imageScore/highestScore(:72/:78)失去来源——保留为兼容字段(值为 null/false)或删;前端 AutoFocusWindow.xaml.cs:149/152 读这两字段,需 D10 同步确认(登记 V-005)。

改点 2(NPE 点2)— getFocusBestPicture 的 compareTo

  • 文件aivfo-data-transmission/.../impl/PictureDAOServiceImpl.java
  • 位置:173-183 方法内 :179 Collectors.reducing((c1, c2) -> c1.getImageScore().compareTo(c2.getImageScore()) > 0 ? c1 : c2) —— getImageScore() 为 null 时 .compareTo 直接 NPE。被 business-manage getFocusBestPicture(ResourceServiceImpl 经 Feign / PictureService:236)调用,"最佳对焦帧"查询触发即崩。
  • 改法:把 reducing 的比较键从 getImageScore 改为 getImageTime(取最新对焦帧)或基于 clearest。即 c1.getImageTime().compareTo(c2.getImageTime()) > 0 ? c1 : c2,并对底层 SQL selectFocusBestPicture 是否仍按分数排序一并核查(若 mapper xml 内有 order by image_score 同步改 image_time)。
  • 为何:本地化后无分数;改最新 image_time 是与"最佳对焦帧=最近一次对焦结果"语义最接近、零数据依赖的判据。
  • 下游受影响buildDetailData(...focusBestPicture...)(ResourceService:283)消费该 Map,判据改后帧选取语义变化——登记 V-005 回归详情时间线。

改点 3(审核新增第三处)— getPictureByDevelopTime AUTOFOCUS 分支 orderByDesc

  • 文件aivfo-business-manage/.../service/impl/ResourceServiceImpl.java
  • 位置:方法 :316-357:333 eq.orderByDesc(PictureDAO::getImageScore);(在 :331-334else(layer 为 null → 查 AUTOFOCUS)分支内)。
  • 后果:SQL 排序不 NPE,但 image_score 全 null 后 orderByDesc 失意义 → "按发育时间取最佳对焦帧"静默选错帧(比 NPE 更隐蔽,04 原文只写"两处"漏了此处)。
  • 改法:333 排序键从 getImageScore 改为 getImageTime(与改点 2 一致,取该发育时间窗内最新对焦帧),即 eq.orderByDesc(PictureDAO::getImageTime);
  • 下游受影响:"按发育时间取最佳对焦帧"的临床展示——登记 V-003c(改判据后临床展示是否仍正确)。

改点 4 / 5(审核新增,排序退化,低优先)— data-transmission 两处 orderByDesc(imageScore)

  • 文件aivfo-data-transmission/.../impl/PictureDAOServiceImpl.java
  • 位置
    • :270 getAutofocusPictureByEmbryoIdAndBatchNumber.orderByDesc(PictureDAO::getImageScore)(原是 focusPointUpdate 调的查询,M3-01 删 focusPointUpdate 后该方法在本链不再被调,但仍是 public service,避免遗留排序退化)。
    • :325 pageQueryPictures 末位 .orderByDesc(...getEmbryoId).orderByDesc(...getImageTime).orderByDesc(PictureDAO::getImageScore)
  • 后果:不崩,但 image_score 全 null 后排序键无意义(对焦图列表/分页次序退化)。
  • 改法:270 排序键改 getImageTime:325 删除末位 .orderByDesc(getImageScore)(前面已有 getEmbryoId + getImageTime 排序,足够稳定)。
  • 登记待验证V-002b(依赖 DB:两处改排序键后对焦图列表/分页次序合理)。

M3-03 · calPhotoPosition 改本地(D5 方案 A:保留接口,输入改本地对焦结果)

D5 已可拍板选 A(审核维度④:calPhotoPosition 只依赖"最清晰位置 clearPosition"这一输入,本地标定的 FocusZ 可直接灌入,改动小、保留云端可追溯)。

现状链路(codegraph 核对)

[旧] AutofocusFeign.calAutoFocusDTO (data-transmission, M3-01已删)
   → Feign → AutofocusApi.calAutofocusPosition
   → AutofocusApiController.calAutofocusPosition  (:35-48, 发布 AutofocusUpdateEvent)
   → AutofocusUpdateEventHandle.handler           (:32-49, 取 clearPosition/mattingSuccessNumber)
   → HousePhotographSettingManageImpl.calPhotoPosition (:50-89)
       - first 分支(:54-68): 初始化, 用 eepromClearPosition 算 AUTOFOCUS 起点+CCD 位置
       - else 分支(:69-88): 用 clearPosition 算对焦起点(:77 calAutofocusStart) + CCD 位置(:84 calCCDPosition), 写 t_house_photograph_setting

calAutofocusStart:125 对焦起点 = clearPosition - (moveDownLayer × verticalMotorSpacePulse)calCCDPosition:145 据 clearestPosition 生成各 CCD 层位置。两者只吃 clearPosition 这个位置值,与打分解耦。

改法(保留 calPhotoPosition 本体,替换上游输入源)

  • 保留不动HousePhotographSettingManageImpl.calPhotoPosition(:50-89)、calAutofocusStart(:104-129)、calCCDPosition(:144-168)、HousePhotographSettingManage 接口(:30)—— 几何换算逻辑完整、与打分无关,整体保留。
  • 改输入源:原 clearPosition 来自 data-transmission focusPointUpdate 选最高分图位置(已删)。新来源为 M2 本地对焦算出的最清晰位置(FocusZ),衔接点二选一(登记 D5-A 落地待定):
    1. 复用 AutofocusApi 入口:保留 AutofocusApiController.calAutofocusPosition(:35-48)作为"本地对焦结果上报"接口,由机旁本地对焦上报 CalAutoFocusPositionParamDTO(clearPosition=本地 FocusZ、mattingSuccessNumber=本地成功层数)→ 仍发 AutofocusUpdateEvent → calPhotoPosition。改动最小:data-transmission 侧的 AutofocusFeign 删了,但 controller 入口保留,改由机旁上报。
    2. 若机旁不经此接口,则新增一个"本地对焦结果接收"入口注入 calPhotoPosition,删 AutofocusApiController/AutofocusApi/AutofocusUpdateEvent(Handle)。
  • 建议:取方案 1(保留 controller 入口)——保留云端可追溯记录、避免删 AutofocusUpdateEvent 链的连锁改动。M3-01 步骤 5 据此不删 AutofocusApiController/AutofocusApi/AutofocusUpdateEvent(Handle),仅其远程调用方从 AutofocusFeign 换成机旁上报。
  • 数据层衔接:本地标定结果存于 house_autofocus_calibration(数据层,M2 产出)。需确认 clearPosition 的脉冲基准与 AutofocusSettingDTO(verticalMotorSpacePulse / moveDownLayer / updateFocusNumber / updateClearestNumber)口径一致——本地 FocusZ 须换算成与原 shootingPosition 同单位的脉冲值再灌入。
  • 为何:A 方案保留 t_house_photograph_setting 写库与下发通道,下位机据此拍照的下游零改动;仅"最清晰位置"的来源从云端打分换成本地标定。
  • 下游受影响first 分支用 eepromClearPosition 仍走 EEPROM 初始化(与 D9 EEPROM 回写硬阻塞相关,本任务不动);else 分支 mattingSuccessNumber 阈值判断(:73/:80)依赖机旁上报的成功层数,需确认本地对焦能提供该值。
  • 登记待验证V-006(依赖微服务集群+DB+真机:本地对焦结果 → calPhotoPosition → 写 t_house_photograph_setting → 下位机拍照位置正确;clearPosition 脉冲基准与 AutofocusSettingDTO 口径一致;mattingSuccessNumber 来源确认)。衔接 M2(本地对焦产出与上报格式)。

M3-04 · 保留链回归核对(② 抠图/clearest 链不受影响)

删 ① 后逐项确认 ② 链与无关链路未被波及。全部为回归验证点(M7 集中测),本任务不改代码,只列清单。

回归点 文件:行号 验证内容 待验证
CCD 抠图加水印 PictureManage.java cutCCD :273-313;PictureProcessingImpl.pictureCropping :48-74(→ Picture.findcircles :30) CCD 图抠图/水印像素级与改前一致 V-R01
收图/抠图/落库/转发主体 ReceivePictureMessageInfo.receive;ReceivePictureCroppingMessage.receive :76-199 CCD 流程收图→抠图→落库→转发完整 V-R02
视频合成 ImageReceiveCompleteEventHandle.imageDataHandle case CCD → saveVideoSpliceInfo :70/:92 CCD 末张触发视频合成正常 V-R03
AI 识别转发(按 CCD clearest) ReceivePictureCroppingMessage.java :172-178(条件 PhotoMode.CCD + CropState.SUCCEED + 层数命中 → PictureIdentifyEvent) AI 仅按 CCD clearest 选图送识别,不读 image_score;文件名层号 currentFocal 正常填充 V-R04
DegreeOfClarity / getClearest 体系 DegreeOfClarity 枚举;getClearestByDevelopTime(ResourceService:121);PictureDAOServiceImpl.getPictureList :117(eq(pictureLayer==0, getClearest, CLEAREST) clearest 查询走下位机标记,与选层打分独立,不受影响 V-R05
ai-middleware / gateway / aivfo-service 全量搜 image_score 无匹配,不改 V-R06 冒烟
下位机定位失败告警 FocusAlarmHandler(用 focusState,与打分无关) 对焦失败告警仍正常触发(非 CLOUD_SERVER_FOCUS_ALARM) V-R07

待验证清单汇总(M7 集中测,本地不可跑)

编号 内容 依赖
V-001 AUTOFOCUS 图到达不再触发对焦回传、仅落库;CCD 视频合成正常 微服务集群+Kafka
V-002 tl-control 不再收 calAutofocusPosition 远程调用、无 Feign 报错、启动无 bean 缺失 微服务集群
V-002b data-transmission 两处 orderByDesc 改 image_time 后列表/分页次序合理 DB
V-003 AUTOFOCUS 走 NOT_OPERATED 落库 image_score=null 不报错;CCD 抠图水印像素级回归 微服务集群+DFS
V-003c getPictureByDevelopTime 改 image_time 后"按发育时间取最佳对焦帧"临床展示正确 DB
V-004 jna 模块编译通过、不加载 getscore;JnaApplication 测试引用同步清理 SpringBoot 工具链
V-005 business-manage 患者详情/对焦预览/最佳帧不 NPE;FocusPreviewPictureVO 字段去留与前端 AutoFocusWindow 同步(D10) 微服务集群+前端
V-006 本地对焦→calPhotoPosition→t_house_photograph_setting→拍照位置正确;脉冲基准/口径一致;mattingSuccessNumber 来源 微服务集群+DB+真机(衔接 M2)
V-007 C# native 打分(HouseBin.cs:2446)与云端 getscore 是否同源/是否随本地对焦废弃(归 M2/合并端,不在本计划改 C# 真机+C# 工程
V-R01~R07 M3-04 保留链回归(抠图/水印/视频/AI/clearest/告警) 微服务集群

风险

  1. 误删 ② 抠图/clearest 链(最高危):cutCCD / pictureCropping / findcircles / DegreeOfClarity.CLEAREST 查询 / eq(PhotoMode.CCD) 任一被误删 → 患者看不到图、AI 不识别、前端展示空白。护栏:删任何代码前确认 PhotoMode——碰 AUTOFOCUS 才删,碰 CCD/CLEAREST 一律保留;改 PictureManage 只动 data-transmission 侧,不碰 ai-middleware 同名类。
  2. 漏改某处 image_score 致 NPE:审核已锁定三处 business-manage 消费(:470/:476、:333)+ data-transmission :179 + 两处 orderByDesc(:270/:325)。任一未改::476/:179 直接 NPE 崩患者详情;:333/:270/:325 静默选错帧/排序退化(更隐蔽)。护栏:M3-02 五个改点全做完再提;M7 V-005/V-003c 专项回归。
  3. 删除顺序违反致编译失败:先删 AutofocusFeign 再删 focusPointUpdate、或先删 pictureScore 再删 cutAutofocus,都会留悬空引用编译失败。护栏:严格按 M3-01"删除顺序"自上而下,连锁删除同一提交完成。
  4. calPhotoPosition 脉冲基准口径错位:本地 FocusZ 若未换算成与 shootingPosition 同单位脉冲就灌入 calAutofocusStart,对焦起点会整体偏移。护栏:V-006 真机验证基准一致。
  5. C# native 打分误判(V-007):若机旁评分另有存档用途却被当旧打分删除,影响机旁数据。护栏:本计划不改 C#,只评估,归 M2/合并端真机确认。

自检

  • 无占位符;所有文件:行号经 codegraph_explore / codegraph_node 核对存在(focusPointUpdate :120-149、:143/:144;AutofocusFeign :25-66、:55;cutAutofocus :331-355、pictureScore :336;PictureProcessingImpl.pictureScore :90-104、:96;Picture.getscore :46;ResourceServiceImpl :462-481(:470/:476)、:316-357(:333);PictureDAOServiceImpl :173-183(:179)、:263-272(:270)、:319-332(:325);ReceivePictureMessageInfo :179;ReceivePictureCroppingMessage buildUpdateDao :226/229、AI 转发 :172-178;calPhotoPosition :50-89、AutofocusUpdateEventHandle :32-49、AutofocusApiController :35-48、AutofocusApi :15-25、AutofocusUpdateEvent :12-95)。
  • 删除顺序按编译依赖拓扑标注,连锁编译错误已点名。
  • 子任务 6 个(M3-01 / M3-01b / M3-02 / M3-03 / M3-04 + 待验证汇总);步骤合计:M3-01 五步 + M3-01b + M3-02 五改点 + M3-03 + M3-04 七回归点。