01-架构与合并方案.md 10 KB

01 · 架构与合并方案(含项目结构全景)

父文档:../00-需求总览.md · 对应需求 1/3 · 决策 D1/D2/D7 目的:把整个时差项目的结构、技术栈、模块依赖讲清楚,并给出合并后的目标架构与落地方案。对着本文应能定位任何要改的代码。


1. 项目结构全景(源码根目录 时差项目源代码/

1.1 .NET 客户端(C# / WPF)

ivf_tl_operate_2.0(机旁操作端 · 合并主体/前台)

ivf_tl_Operate.sln
├── ivf_tl_Operate/         主程序(MVVM)
│   ├── MainWindow.xaml      单窗口+ContentControl页面切换;写死 1824×2736
│   ├── App.xaml(.cs)        单实例Mutex"ivf_tl_Operate"+全局异常+多语言
│   ├── View/                页面:MainPage/Detail/DishRecord/Chart/Alarm/Photo/
│   │                        Setting/HouseSetting/AutoFocusSetting/HouseDebug/Buffer/About
│   ├── ViewModel/           对应 VM(MainPage/HouseDebug/AutoFocus/Alarm/Chart...)
│   ├── Windows/             LoginWindow/GetDate/Message/PhotoWindowNew
│   ├── CustomUserControls/  CustomHouseInfo(圆形舱)/StatusControl/PhotoBox/...
│   └── Resources/Language/  Chinese.xaml / English.xaml
├── ivf_tl_Entity/          实体 + ★硬件访问(operate自带一套)
│   ├── ComEntitys/          ComBin.cs / SerialBin.cs(串口)
│   └── CameraEntitys/       Camera.cs(相机)
└── ivf_tl_Services/        HttpHelper / MqttHelper / LogHelper

ivf_tl_control_2.0(机旁采集/控制服务 · 合并并入/后台)

ivf_tl_Control.sln
├── ivf_tl_Control/         入口 StartMain.cs(StartRun→InitTL→InitHouse) + AppData.cs
├── ivf_tl_ControlTest/     启动壳 Window1(★登录窗,合并后删) + App.config
├── ivf_tl_CameraHelper/    Camera.cs/MVCAPI.cs/CapInfoStruct(相机,static锁)
├── ivf_tl_Com/             HouseBin.cs(舱主循环)/BufferBottleBin/SerialBin
├── ivf_tl_SerialHelper/    Channel.cs(SerialPort)/RingBufferManager/Util/ComBin
├── ivf_tl_Controller/      HouseBinController(对焦/CCD位置)/SerialBinController
├── ivf_tl_Services(Impl)/  DB/Http/Kafka/Log/Mqtt 服务
├── ivf_tl_Entity/          CustomProtocol.cs(协议)/DTO/DBEntitys
└── ivf_tl_UtilHelper/      AivfoHelper(native抠图打分)/Path/Convert/String

autofocustool(独立自动对焦 · 算法移植源)

├── Calib/CalibrationEngine.cs    四步标定(粗对焦→居中→曝光→精对焦)
├── Imaging/Sharpness.cs(÷mean) / WellDetector.cs / ExposureMeter.cs
├── Serial/Protocol.cs / SerialMotor.cs / HouseMotor.cs   下位机协议(权威)
├── Camera/Camera.cs / MVCAPI.cs                          相机
├── Calib/CalibrationFile.cs / CalibrationManager.cs      标定结果JSON
└── calibration.json                                       标定结果(未回写EEPROM)
(SelfTest/SmokeTest/Calibrate/CalibTest/MainWindow/CalibWindow = 测试外壳,不移植)

aivfo-front-manament-2.0(中央管理端 · 不重做,评估影响)

ivf_tl_Manage.sln
├── ivf_tl_Manage/  MainWindow/DevManageView/DeviceInfoUserControl/
│                   ResolutionAdapter.cs(按1920×1080递归缩放)/Win/AutoFocusWindow
├── ivf_tl_Entity/  TLSetting 等
└── ivf_tl_Service/ HttpServiceCall / MqttHelper(订 TL/House/pc)

1.2 Java 微服务(Spring Boot + Nacos + MyBatis-Plus + Kafka/MQTT)

统一分层:controller / service / service-impl / manage / mapper / entity / facade / rpc / lanucher(有 lanucher = 可独立启动)。

微服务 职责 关键
aivfo-gateway 网关 + 认证授权 /api/gateway/auth/login
aivfo-business-manage 病例/胚胎/字典业务(25 表) /api/businessManage/...
aivfo-data-transmission 收图/抠图/选层打分/视频合成(4 表,OpenCV JNA) ★选层删除见 04
aivof-tl-control 舱室控制 + MQTT 编排 + 对焦几何换算(17 表) calPhotoPosition
aivfo-ai-middleware AI 胚胎识别 按 CCD clearest 选图
aivfo-service 通用/聚合(告警联系人/日志,2 表)
aivfo-framework 公共 starter(mybatis-plus/nacos/safety/log/quartz) 不改

数据库:见总纲 §1.2(5 业务库 + 框架表,脚本在 sql/)。


2. 合并形态(D1:单进程托管)

结论:operate 为主进程(WPF 前台),启动时托管 control 的 StartRun() 作为后台线程;删除 control 的 Window1 登录窗与独立 UI;全程序单一登录入口(operate 的 LoginWindow)。类比 360:一个主界面 + 常驻后台服务。

落地步骤

  1. 把 control 各子工程(Com/CameraHelper/SerialHelper/Controller/Services/Entity/Util)作为类库并入合并解决方案。
  2. operate 启动、登录成功后,调用 StartMain.StartRun()(去掉其中弹 MessageBox + SendMessage 点 Yes 的 hack,改为静默/日志)。
  3. control 的 AppData 单例与 operate 的 AppData 单例命名冲突需消解(两边都有 AppData.cs)——合并时改命名空间或合并为统一应用上下文。
  4. control 原 Window1 的登录/初始化逻辑(读 App.config 账号)并入 operate 登录后的初始化流程。

3. 统一硬件访问层(D2:本轮技术地基)

问题:operate、control、autofocustool 各有一套 ComBin/SerialPort/Camera。合并进一个进程后,调试页开 COM/相机时 control 后台也在占用同一资源 → 串口独占冲突、相机 MVCAPI 句柄争用(control 的 Camera 已用进程内 static 锁,但跨"采集 vs 调试"仍会互相阻塞)。

方案

            ┌─────────────────────────────┐
   采集 ───►│  HardwareAccessLayer (单例)    │
   调试 ───►│  - 每 COM 口唯一 ComBin 持有者  │
   对焦 ───►│  - 每相机唯一 Camera 持有者     │
            │  - 按舱 信号量/锁 互斥          │
            │  - 统一 Open/Close/借用/归还    │
            └─────────────────────────────┘
  • 全进程唯一持有每个 COM 口与每台相机的句柄。
  • operate 调试、control 采集、自动对焦都向它借用,不再各自 new ComBin/new SerialPort/new Camera
  • 互斥/排队:进入调试或对焦时暂停 control 对该舱的采集任务;同一舱同一时刻只有一个使用者。
  • 统一关闭路径:杜绝句柄泄漏(现状调试页有自己的 ClosePort/UnInit,进程异常退出可能泄漏)。
  • 下位机串口协议统一到一套(autofocustool 的 Protocol.cs 最权威,见 03/10)。

最小验证(M1 必过):单进程里"调试取一帧图"与"control 后台采集"切换,不报端口占用/不死锁。


4. 不可退出 / 常驻(需求 3 · D7)

现状:operate 无 OnClosing 拦截、WindowStyle=None;control 的关闭倒计时 StopWindow 与 MQTT 保活都被 return; 注释禁用(半成品)。

目标

  • 屏蔽常规关闭:标题栏关闭/Alt+F4/最小化误触/任务栏退出。
  • 唯一退出:任务管理器结束进程。
  • 🔶D7 待定:是否保留隐藏管理员退出(长按+密码)。
  • 配套(R5):进程常驻必须配崩溃自愈——看门狗/异常隔离/自动重启采集线程/热更新策略;不能因为"不可退出"导致出问题只能杀进程。

5. 代码隔离原则(应对老代码坑 R3/屎山)

  1. 不顺手重构老逻辑(风险见 02 §闭环);用硬件访问层等新接口把老代码包起来,新功能只依赖接口。
  2. 改前用 CodeGraph/调用链查影响面(注:CodeGraph 对 C#/Java 符号节点提取有限,必要时直接读调用方)。
  3. 死代码先不删(注释块、Hidden 控件),合并稳定后再清理。
  4. 关键 hack 单独记录(如 control 启动 SendMessage 点弹窗 Yes、明文密码、tl13579 口令)。
  5. 整目录退役判据(何时可删 ivf_tl_control_2.0 / autofocustool——二者均为"合并/移植源",删除是合并收尾动作,必须满足判据再删(删除排期落 M1/M2 子计划):

| 目录 | 现状(2026-06-18) | 可删判据(全满足才删) | |---|---|---| | autofocustool(算法/协议移植源) | 编译上已无任何工程引用(四步标定算法已移植入 IvfTl.AutoFocus,见 M2-01;其余为"测试外壳"不移植)。但它是 Protocol.cs 下位机协议权威与对焦算法的逐行比对参照 | M2 真机验证通过(V-020/对焦链 V-041~V-067):移植后的对焦/协议在真机与原 autofocustool 结果一致 | | ivf_tl_control_2.0(合并并入源) | operate 仍以 3 条 ProjectReference 直接引用ivf_tl_Control / IvfTl.Hardware / IvfTl.AutoFocus(ivf_tl_Operate.csproj:624/627/630);删除即编译失败 | ① M1 真机验证通过(V-011~V-016/V-017~V-029) ② 被引 3 工程(及传递依赖)物理并入 operate 合并解决方案 ③ 消解 operate/control 同名程序集(ivf_tl_Entity/ivf_tl_Services)身份冲突(§2 步骤3) ④ 改完引用编译 0 error |

注:二者均在 git 初始提交(b474804),删后仍可从历史找回;验证期保留本地副本仅为比对/排障便利。


6. 本专题验收

  • 单进程启动:operate 前台 + control 后台线程,无 control 登录窗。
  • 硬件互斥最小验证通过(§3)。
  • 退出屏蔽生效,崩溃能自愈(不靠人杀进程)。
  • 合并后既有功能不回归失败(基线对比,见 09)。

7. 全量操作日志(架构补充,见 14)

合并端 operate / front 及各 Java 微服务的所有操作经统一日志体系记录:

  • 新增日志微服务 aivfo-oplog(注册 Nacos,消费 Kafka tl-oplog → 写 logoperation_log,管理保留期)。
  • C# 端新增可复用组件 Aivfo.OperationLog(异步队列→Kafka,关键边界封装 + 全埋);Java 端复用 aivfo-log-spring-boot@OperateLog 切面。
  • traceId/parentId 全链路串联 C#↔Java;调试级详细日志走本地文件。
  • 详见子文档 14。