Files
StandardSence/Doc/StandardScene拆分计划.md
T
zhaowei.huang a0dc1e6cd0 refactor: 插件 UI 从 WinForms 迁移到 CycleGUI,并修复代码质量问题
将 StandardScene 各插件的配置/监控窗体从 WinForms 迁移到 CycleGUI(删除 .Designer.cs/.resx,重写为 PanelBuilder 立即模式 UI,新增 CycleUiHelper 统一对话框)。

同时修复代码审核中的问题:
- 后台文件写入加锁 + try/catch(ButtonBoxManager / DoorManager,对齐 LoopViewer.SaveTasks 模式)
- CoderFieldsMetadata.cs 启用 #nullable enable,消除 CS8632 警告
- DummyCar 移除已废弃的 rightClickAction()/SetPosition()
- CarRemoteHelper.OpenVehicleWebPage 的 Process.Start 加 try/catch
- 重命名名不副实的 Mstsc()(现为打开网页)
- 统一弃元命名为 _
- TrafficInterlockViewer 改用稳定 Id(GUID)做选择/编辑,替代行索引
- csproj 改用 $(CGUILibDir) 解析 CycleGUI,绝对路径收敛到 Directory.Build.props

构建:dotnet build StandardScene.sln → 0 错误,30 警告(均为历史遗留)。
注:static 单例状态重构(审核第 8 项)暂未处理,留待单独任务。
2026-06-26 15:00:53 +08:00

614 lines
51 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.
# StandardScene 插件化拆分计划(导航场景插件化 · Phase C 落地)
> 版本:草案 **v2**(按评审反馈更新)
> 编写依据:对当前工程 `E:\Work\Core\Simple-FR\StandardSence`.NET Framework 4.8 单体插件)的**逐文件精读**。
> 上游设计:承接并细化《配置向导与导航场景插件化设计.md》第 5 节「StandardScene 拆分」与第 11.3 节「Phase C」。
> 本文目标:把上游"框架级"拆分意图,落地为**基于真实代码事实、可直接执行**的文件级/类级拆分计划。
> 范围声明:本文原为**计划文档**。**自「会话1」(2026-06-09) 起已开始落地实施**,实际进度与代码现状见 **§11 实施进度记忆**(含已落地改动、当前可编译状态、待确认阻塞项)。
### ⚠️ 架构决策变更(2026-06-12,用户拍板):「磁 / 二维码 / 激光」三场景 → **两场景平台**
原计划的 `Magnetic` / `QrCode` / `Laser` 三个导航 dll 调整为 **两个场景平台插件**(已落地,全解决方案 0 错误):
| 插件 dll | scene id | 内容 | 说明 |
|---|---|---|---|
| `StandardScene.Magnetic.dll` | `scene.mag` | Kiva、MultiWheelLifterCar + `MagneticTrackCoder` | 磁导航平台(保留车型上的 Qr 地标段能力) |
| `StandardScene.QrLidar.dll` | `scene.qrlidar` | Forklift、MultiWheelForkLifter、DualLiftingCar、MultiVehicleCar、ArmCar + `SyncQrMap` | 激光+二维码融合平台:激光坐标导航由内核 `GhostCar.BasicGo` 兜底,`QrGo` 按轨道 tag 逐段触发,**融合或单独使用均可** |
| `StandardScene.Devices.dll` | `scene.device` | 不变 | 清单 id 由 `devices` 规范化 |
| `StandardScene.Protocol.VDA5050.dll` | `scene.vda5050` | 不变 | 清单 id 由 `protocol.vda5050` 规范化 |
关键机制结论与配套改动:
1. **车型按平台归位**(推翻 v2 "车型留基座"):依据 = 项目存档按**短类名**(`JSONLoader``type.Name.ToLower()`)匹配车型,类迁 dll 不破坏旧存档;coder 特性 `GetCustomAttributes(inherit:true)` 沿继承链收集,内核 `GhostCar` 的 BasicGo 天然被所有车型继承。
2. **共享字段袋下沉基座**`KivaFields.cs` / `MultiWheelLifterFields.cs`ArmCar、MultiVehicleCar 跨平台继承它们);`IScriptErrorRecoverable` 接口解耦 `AbstractLoopMission` 对 Kiva 的反向依赖。
3. **清单命名修正**:内核只识别 `<dll>.scene.json`,原裸 `scene.json` 永远不会被扫描到——已全部改名并规范 id。
4. **内核配套**Simple 仓库):① `Startup.LoadPlugins` 两阶段加载——清单 `requiresCore` 声明的基座(`StandardScene.dll`)自动并入 alwaysLoad 且 **non-collectible 先行加载**(否则衍生插件的 collectible ALC 解析不到基座,运行期必炸);② `SceneManifest.navKinds` 多导航声明 + `INavigationProfile.Kinds`qrlidar 同时覆盖 Laser+QrCode`FindByKind` 按集合匹配);③ `ShouldLoad` 规则改为「**有清单(含设备/协议)即参与激活判定**,无清单兼容全加载」,scene.device 因此可被选择性加载。
5. **平台配套**Migu2.0):`DeploymentProfile.NavKindToSceneId` 改映射 magnetic→scene.mag、qrcode/laser→scene.qrlidar;向导写 active-scenes.json 时固定并入 scene.device。
### v2 评审反馈要点(本次更新依据)
1. **宿主切换**StandardScene 改为依赖 **`SimpleLite`net8.0****老 `SimpleComposer.exe`(net4.8)废弃**。内核引用层(命名空间 `SimpleComposer.RCS``SimpleLite.RCS` 等)正由**另一个 AI 会话**同步改造,本文按新宿主表述。
2. **目标框架统一 `net8.0`**(与 SimpleLite 一致;**非 net8.0-windows**)。SimpleLite UI 采用 **CycleGUI**、WebApi 采用 **EmbedIO**,故 StandardScene **需去除 WinForms 依赖**,窗体迁移到 CycleGUI 或平台 Web。
3. **设备驱动必须独立 dll**,且**支持热卸载/加载**(配合 SimpleLite `/plugins` reload/unload + collectible ALC)。
4. **`FactoryTest` 与松灵残留:直接删除**,不纳入 Core,也不纳入 Customer。
5. **`WebApi.cs` 是面向老平台的 Nancy 接口**:本次**整理后暂留 Core**,**后期废弃**,能力迁移到 SimpleLite 接口(见 `E:\Work\Core\Simple-FR\Simple\SimpleLite\Docs\MIGU-API.md`)。此版本先保留。
---
## 0. TL;DR(结论先行)
1. **导航方式与车型是正交的两个维度**。导航(磁 / 二维码 / 激光)由**轨道/站点字段 + TrackCoder**决定,不是车型固有属性;同一车型(如 `Kiva`)的类上**同时**挂磁、二维码、激光避障三类 coder。上游"按车型整包切到某导航 dll"**切不干净**,修正为「**车型留基座 + 导航能力抽离为可插拔 coder**」。
2. **激光"避障"(LidarArea) ≠ 激光"导航定位"(LidarMap/SLAM)**:避障通用留 Core,仅 SLAM 地图进 Laser。
3. **`WebApi.cs`(123KB) 是老平台 Nancy 接口**,导航耦合极弱(仅二维码 `QrMap`、激光 `getLidarMap`)。**整理后暂留 Core,标记 deprecated,后期迁 SimpleLite EmbedIO 接口**(§4.7 给出端点映射)。
4. **存在大量重复代码**可借本次"抽离标准功能"沉淀:磁导航循迹器写了**两份**`newReset/newTrafficReset` 在 3 个车型复制、`SetDisplayInfo/GetCarStatus/Mstsc/EmergencyStop` 雷同。
5. **三个正交维度**:①导航(磁/二维码/激光) ②车型(顶升/叉车/Kiva/机械臂…) ③设备驱动(充电桩/门/按钮盒)。设备驱动**独立成可热插拔 dll**。
6. **VDA5050 是自成一体的 MQTT 协议栈**,独立 dll。
7. **两大技术主线**:① 把 TrackCoder 从"编译期特性硬绑定车型"改为"导航插件运行期注册",需内核 `SimpleCore` 配合;② **net4.8 → net8.0 迁移**:换宿主(SimpleComposer→SimpleLite+ **去 WinForms(窗体迁 CycleGUI/Web**
---
## 1. 现状盘点(基于代码事实)
### 1.1 工程概况(来自 `StandardScene.csproj`
| 项 | 现状 | 目标(本次方向) |
|---|---|---|
| 输出类型 | `Library`(插件) | 多个 `Library` 插件 dll |
| 目标框架 | `.NET Framework 4.8` | **`net8.0`**(与 SimpleLite 一致,去 WinForms |
| 宿主 | `SimpleComposer.exe`(net4.8) | **`SimpleLite`(net8.0)**,老 Composer 废弃 |
| 契约引用 | `RefSimpleCore.dll` + `SimpleComposer.exe` | **`SimpleCore`(netstandard2.0/net8) + `SimpleLite` 程序集** |
| UI | `System.Windows.Forms`(大量窗体) | **CycleGUI / 平台 Web**(移除 WinForms |
| 对外接口 | `WebApi.cs`Nancy 1.4.5 | 暂留 Core;后期迁 **SimpleLite EmbedIO**MIGU-API |
| 其它程序集 | `CommonUsage``MDCSToolBox``leegKeys-sdk``LessokajiWeaverUtilities` | 随归属 dll 保留/下沉 |
| NuGet | `MQTTnet``EasyModbusTCP``IoTClient``Jint``Nancy(1.4.5)``Newtonsoft.Json``DocumentFormat.OpenXml` | 随归属拆分(Nancy 验证 net8 兼容或对齐 SimpleLite 的 Nancy 2.0 |
| 产物落地 | `PostBuildEvent` 拷 dll → `build\plugins\` | 各 dll + `scene.json` → SimpleLite `plugins\` |
### 1.2 模块与文件分组(约 110 个有效 `.cs`)
| 目录 | 内容 | 现状性质 |
|---|---|---|
| `CarTypes/` | `Forklift``Kiva``ArmCar``DualLiftingCar``MultiWheelForkLifter``MultiVehicleCar``MultiWheelLifterCar``DummyCar``UselessCar``BasicFields``VehicleMonitor`(窗体) | 车型 + 内联导航 coder |
| `CarTypes/VDACar/` | `VDA5050Car``VDA5050Commons/Helper/Interface/Segment/WebApi``MasterMQTTCommunication``TextViewer`(窗体) | VDA5050 通信协议栈 |
| `Chained/`(含 `Loop/` | 搬运/环线任务 + `DeliveryViewer/LoopViewer`(窗体) | 任务调度 |
| `Charge/` | 充电任务 + `ChargeStation*`/`ChargeStrategy*`/`Alarm*`/`Communication*` + 多个 `*Form`(窗体) | 充电逻辑 + UI/服务 |
| `ChargeStationType/` | `AbstractChargeStation``FL`/`MuXing`/`PCB` | 充电桩厂商驱动 |
| `InterLock/` | `AbstractInterlockMission``TrafficInterlockMission``TrafficInterlockViewer`(窗体) | 互锁/交管 |
| `Scheduler/` | `HeartBeat`/`NodeIsEnable`/`RegionalTrafficControl`/`SecuritySignal` Mission | 调度信号 |
| `ExtendDevice/Door/` | `BasicDoorController``ModbusDoorController``DoorMission``DoorTypeAttribute``DoorManager/DoorMonitor`(窗体) | 门控驱动 |
| `ExtendDevice/ButtonBox/` | `BasicButtonBox``LeegButtonBox`/`AzowieButtonBox``ButtonMission``ButtonBoxManager`(窗体) | 呼叫器驱动 |
| `Model/` | `Map`(含 `LidarMap`)、`SimpleMap``TaskModel``LoopTask`、各 `*Setting``VehicleStatus``MissionState``MapStructure` | 数据模型 |
| `Utils/` `TCP/` `CommonTools/` | Json/Modbus/WebAPIHelper、AsyncTcpClient、Snowflake/AtomicFile | 基础设施 |
| 根 | `Commons.cs``Heuristic.cs``LadderLogic.cs``StandardCADTool.cs``WebApi.cs``FactoryTest.cs` | 公共 + 契约 + 老 API + 产测 |
### 1.3 车型清单与继承
| 车型类 | `[CarType]` | 基类 | 关键特征 |
|---|---|---|---|
| `Kiva` | "Kiva" | `GhostCar` | 内联磁 coder `AllCarMagTrackCoder` + Qr + 避障 + 取放货 + `KivaCarTrackCoder`(转弯) |
| `Forklift` | "叉车" | `GhostCar` | 避障 + 取放货(无显式磁/二维码) |
| `MultiWheelLifterCar`(CarTypes) | "多舵轮顶升车" | `GhostCar` | 内联磁 coder `MagTrackCoder` + Qr + 钻车/夹抱 |
| `MultiWheelForkLifter` | "多舵轮叉车" | `GhostCar` | 简化取放货 |
| `MultiVehicleCar` | "多车联动AGV" | `GhostCar` | 多车 sync + Qr + 钻车 |
| `DualLiftingCar` | "锂电双举升" | `GhostCar` | 无 coder(仅 UI/测试) |
| `ArmCar` | "ArmCar" | `GhostCar` | 机械臂动作;**依赖 `VDA5050SiteField`**、继承 `Kiva*Fields` |
| `DummyCar` | "模拟车-包络" | `Car` | **命名空间 `AMRScene1`**`Jint` 仿真 |
| `UselessCar` | (已注释,未注册) | `GhostCar` | 测试残留 |
### 1.4 Mission 继承体系(均派生内核 `Mission`,导航无关)
```
Mission
├─ AbstractChainedDeliveryMission / ChainedDeliveryMission(→TransportDelivery) Chained/
├─ AbstractLoopMission(→LoopMission) Chained/
├─ TrafficInterlockMission / AbstractInterlockMission InterLock/
│ └─ AbstractChargeLogiceMission(→StandardChargeMission) Charge/
├─ HeartBeat/NodeIsEnable/RegionalTrafficControl/SecuritySignal Mission Scheduler/
├─ DoorMission / ButtonMission ExtendDevice/
└─ FactoryTest(产测,本次删除) 根
```
### 1.5 设备驱动体系(第三正交维度,本次独立 dll + 热插拔)
- 充电桩:`AbstractChargeStation``FLChargeStation` / `MuXingChargeStation`(牧星) / `PCBChargeStation``ChargeStationType` 枚举;`StandardChargeMission``car.fields["MuXing"]` 区分 FRLD/MuXing。
- 门:`BasicDoorController``ModbusDoorController``DoorTypeAttribute`(注册契约)。
- 按钮盒:`BasicButtonBox``LeegButtonBox`(依赖 `leegKeys-sdk`/`leegiot`) / `AzowieButtonBox`
### 1.6 VDA5050 子系统(独立 MQTT 协议栈)
- `VDA5050Car : Car` + `MasterMQTTCommunication` + `VDA5050Interface/Helper/Commons/Segment/WebApi` + `TextViewer`(窗体);依赖 `CommonUsage.Protocols.VDA5050.*` + `MQTTnet`
- VDA5050 车端自管导航定位,与磁/二维码/激光维度无关。
- 耦合点:`ArmCar` 引用 `VDA5050SiteField`(拆分时解依赖)。
### 1.7 删除项(拆分前清理,**不进 Core/Customer**
| 文件/类 | 原因 | 处置 |
|---|---|---|
| `FactoryTest.cs` | 产测专用,非标准能力 | **删除**(评审已确认) |
| 根 `SongLingDeliveryViewer.Designer.cs` | 松灵客户残留,仅 `.Designer.cs`、无主文件、未被 `csproj` 收录 | **删除** |
| 根 `MultiWheelLifterCar.cs` | 与 `CarTypes/MultiWheelLifterCar.cs` 重名旧文件,**未被 `csproj` 收录**(死文件) | **删除** |
| `CarTypes/UselessCar.cs` | `[CarType]` 已注释、仅反射示例 | 删除(或移测试样例) |
---
## 2. 关键洞察(精读结论 → 对上游设计的修正)★
### 2.1 洞察 A:导航是"轨道/站点字段 + Coder",与车型正交
- `CarTypes/BasicFields.cs:23` `TagValue //磁导航,二维码值,或者rfid 值`(站点字段)。
- 磁:`Kiva.cs:37``CarTypes/MultiWheelLifterCar.cs:34` `track.fields["Magnet"]`/`NaiveMagnet`(轨道字段)。
- 二维码:车型 coder `useVerb="dst.tag>0 && src.tag>0"``agv.QrGo(...)`
- 激光避障:`useVerb="track.LidarArea != -2"``agv.SwitchLidarArea(...)`
- **结论**:同一车型在不同轨道字段下走不同 coder 分支;按车型切 dll 会复制车型或丢能力。
### 2.2 洞察 B:导航逻辑以"特性"内联在车型,且多导航混杂
- `[TemplateTrackCoderSettings]`/`[ProgramTrackCoderSettings(program=typeof(...))]` 编译期硬绑定到车型类型。
- `Kiva` 同时挂磁(prio19)+二维码(prio30)+避障+取放货。
- **结论**:导航 dll 要可插拔地为车型提供 coder,必须把 coder 外置并由内核支持**运行期注册**(§7.1)。
### 2.3 洞察 C:激光"避障" ≠ 激光"导航定位"
- 避障:`LidarArea`/`SwitchLidarArea`/`ChangeAvoidanceDistance`/`FrontLidarDetect`——几乎所有车型都有,通用 → Core。
- 定位:`Model/Map.cs:183 LidarMap`(拉 `127.0.0.1:4321` SLAM 栅格) + `WebApi.cs:1021 /map/getLidarMap` → Laser。
### 2.4 洞察 D:可"抽离为标准功能"的重复代码
| 重复项 | 位置 | 抽离目标 |
|---|---|---|
| 磁循迹器(选路+`MagGo/NaiveMagGo` | `Kiva.cs:32 AllCarMagTrackCoder``CarTypes/MultiWheelLifterCar.cs:29 MagTrackCoder` | 合并为唯一 `MagneticTrackCoder`(Magnetic dll) |
| `newReset/newTrafficReset` | `Kiva.cs:715``Forklift.cs:279``CarTypes/MultiWheelLifterCar.cs:347` | 上提 Core 车型基类 |
| `SetDisplayInfo` | 各车型雷同 | Core 基类默认实现 |
| `Mstsc/EmergencyStop/ResetClumsy`(HTTP:8008) | 多车型重复 | Core 基类 |
| 避障/IO/纠偏 coder 模板 | 各车型重复粘贴 | Core 通用 coder 模板集 |
| `GetCarStatus` | `Commons``MultiWheelForkLifter` 各一份 | 统一 `Commons` |
### 2.5 洞察 E`WebApi.cs` 是老平台 Nancy 接口,整体面临废弃
- `ApiController : NancyModule`(`WebApi.cs:35`)40+ 端点;导航相关仅二维码 `QrMap`(`:38/:40/:2050`)+`QrSite`(`:2807`) 与激光 `getLidarMap`(`:1021`)。
- 其能力在 SimpleLite 已由 **EmbedIO**`/projection/*`(投影快照 + reflection + map-edit + scenes,见 MIGU-API.md)覆盖。
- **处置(本版)**:整理后**暂留 Core**(标 `[Obsolete]`/注释 deprecated);**后期整体废弃**,迁移索引见 §4.7。
### 2.6 洞察 F:设备驱动是第三个正交维度(本次独立 dll + 热插拔)
- 充电桩/门/按钮盒按厂商/型号扩展,与导航、车型都正交。
- 通过既有特性(`ChargeStationType`/`DoorTypeAttribute`/新增 ButtonBoxType)注册,编译为独立 `Devices.*` dll,支持 SimpleLite `/plugins` 热加载/卸载。
### 2.7 洞察 GUI 形态需从 WinForms 迁到 CycleGUI/Webnet8.0 约束)
- SimpleLite = `net8.0`(纯)、UI 用 **CycleGUI**、WebApi 用 **EmbedIO****不依赖 `System.Windows.Forms`**。
- StandardScene 现有窗体:`DeliveryViewer/LoopViewer/TrafficInterlockViewer/VehicleMonitor/各 Charge*Form/Door*/ButtonBox*/TextViewer` + `Commons``MessageBox`
- **统一 net8.0 ⇒ 必须移除 WinForms**:窗体迁 **CycleGUI**SimpleLite 立即模式 UI)或平台 **Web**`MessageBox` 类提示改 CycleGUI 弹窗 / 平台通知。这是本次**重要工作量与风险**。
---
## 3. 目标架构与目录规划
### 3.1 分层依赖图
```mermaid
flowchart TD
SC["SimpleCore (netstandard2.0/net8)<br/>AbstractCar/CarType/Mission/ITrackCoder/Heuristics<br/>+ 导航契约 NavKind/INavigationProfile/ISceneContext<br/>+ (新增)TrackCoder 运行期注册表"]
SL["SimpleLite (net8.0 宿主)<br/>CycleGUI UI · EmbedIO WebApi · /plugins 热插拔 · /scenes 选择性加载"]
CORE["StandardScene.Core (net8.0)<br/>导航无关基座:车型本体+任务/充电/互锁/调度+模型/工具+Commons+通用避障coder<br/>(暂留)WebApi.Core(Nancy, deprecated)"]
MAG["StandardScene.Magnetic"]
QR["StandardScene.QrCode"]
LAS["StandardScene.Laser"]
VDA["StandardScene.Protocol.VDA5050"]
DCH["StandardScene.Devices.Charge<br/>(热插拔)"]
DDR["StandardScene.Devices.Door<br/>(热插拔)"]
DBT["StandardScene.Devices.ButtonBox<br/>(热插拔)"]
SC --> CORE
SC --> SL
CORE --> MAG & QR & LAS & VDA & DCH & DDR & DBT
SL -. 加载/卸载 .-> CORE & MAG & QR & LAS & VDA & DCH & DDR & DBT
```
### 3.2 解决方案目录布局(单工程 → 多工程,统一 net8.0)
```
StandardScene/ 解决方案根
├─ StandardScene.Core/ net8.0,标准基座(alwaysLoad,不单独作为导航场景)
│ ├─ Navigation/ INavigationProfile/NavKind/ISceneContext/Registry
│ ├─ Cars/ 车型基类 StandardCarBase + 各车型本体(无导航 coder、无 WinForms
│ │ └─ Sim/ DummyCar(仿真,AMRScene1 命名空间收敛)
│ ├─ Coders/ 通用 coder(避障/IO/纠偏/取放货模板)
│ ├─ Chained/ Charge/ ChargeStationType(抽象) / InterLock/ Scheduler/
│ ├─ ExtendDevice/ 设备框架(基类 + 注册特性)
│ ├─ Model/ Utils/ TCP/ CommonTools/
│ ├─ Ui/ CycleGUI 面板(替代原 WinForms 窗体)
│ ├─ Commons.cs Heuristic.cs LadderLogic.cs StandardCADTool.cs
│ └─ WebApi.Core.cs 老 Nancy APIdeprecated,暂留,后期删)
├─ StandardScene.Magnetic/ → plugins/ + scene.json
├─ StandardScene.QrCode/ → plugins/ + scene.json
├─ StandardScene.Laser/ → plugins/ + scene.json
├─ StandardScene.Protocol.VDA5050/ → plugins/ + scene.json
├─ StandardScene.Devices.Charge/ → plugins/(热插拔)
├─ StandardScene.Devices.Door/ → plugins/(热插拔)
├─ StandardScene.Devices.ButtonBox/ → plugins/(热插拔)
└─ StandardScene.sln
```
### 3.3 各 dll 职责
| dll | 职责 | 可激活/热插拔 |
|---|---|---|
| `StandardScene.Core` | 导航无关一切:车型本体、任务/充电/互锁/调度、模型/工具、`Commons`/契约、通用避障 coder、(暂留)老 WebApi | 基座(`alwaysLoad` |
| `StandardScene.Magnetic` | 统一 `MagneticTrackCoder` + 磁条字段语义 | 是 |
| `StandardScene.QrCode` | `QrTrackCoder` + `SyncQrMap` + 二维码地图下发 | 是 |
| `StandardScene.Laser` | `LidarMap`/`getLidarMap`SLAM | 是 |
| `StandardScene.Protocol.VDA5050` | VDA5050/MQTT 协议栈 + `VDA5050Car` | 是 |
| `StandardScene.Devices.Charge` | 充电桩 FL/MuXing/PCB 驱动 | **是(热插拔)** |
| `StandardScene.Devices.Door` | 门 Modbus 驱动 | **是(热插拔)** |
| `StandardScene.Devices.ButtonBox` | 按钮盒 Leeg/Azowie 驱动 | **是(热插拔)** |
---
## 4. 功能归属矩阵(文件级 / 类级)★
> 动作:**移动**/**拆分**/**抽离**/**保留**/**删除**/**迁UI**(WinForms→CycleGUI/Web)/**待复核**。
### 4.1 车型(`CarTypes/`
| 现状 | 目标 | 动作 | 说明 |
|---|---|---|---|
| `BasicFields.cs` | Core | 移动 | 车型公共字段 |
| `Kiva.cs::Kiva` | Core(Cars) | 拆分 | 本体留 Core;移除内联磁/Qr coder 特性 |
| `Kiva.cs::AllCarMagTrackCoder` | Magnetic | 抽离 | 并入唯一 `MagneticTrackCoder` |
| `Kiva.cs::KivaCarTrackCoder` | Core(Coders) | 移动 | 转弯,导航无关 |
| `Forklift.cs` | Core(Cars) | 移动 | 通用避障/取放货 |
| `CarTypes/MultiWheelLifterCar.cs::MultiWheelLifterCar` | Core(Cars) | 拆分 | 本体留 Core;移除内联磁/Qr |
| `CarTypes/MultiWheelLifterCar.cs::MagTrackCoder` | Magnetic | 抽离 | 并入 `MagneticTrackCoder`(去重) |
| `MultiWheelForkLifter.cs` | Core(Cars) | 移动 | `GetCarStatus` 并入 `Commons` |
| `MultiVehicleCar.cs` | Core(Cars) | 拆分 | 联动留 CoreQr coder 外移 QrCode |
| `DualLiftingCar.cs` | Core(Cars) | 移动 | 无 coder |
| `ArmCar.cs` | Core(Cars) | 拆分/解耦 | 解除 `VDA5050SiteField` 依赖 |
| `DummyCar.cs` | Core(Cars/Sim) | 移动 | `AMRScene1` 命名空间收敛 |
| `UselessCar.cs` | — | 删除 | 未注册 |
| `VehicleMonitor.cs(.Designer)` | Core(Ui) | **迁UI** | WinForms → CycleGUI |
### 4.2 VDA5050`CarTypes/VDACar/`
| 现状 | 目标 | 动作 |
|---|---|---|
| `VDA5050*` + `MasterMQTTCommunication` | `Protocol.VDA5050` | 移动(整子目录) |
| `TextViewer.cs(.Designer)` | `Protocol.VDA5050`(Ui) | 迁UICycleGUI |
| `VDA5050SiteField`(被 ArmCar 引用) | Core 公共字段 或 VDA dll | 待复核(ArmCar 留 Core 则下沉 Core |
### 4.3 任务族(`Chained/` `InterLock/` `Scheduler/`
| 现状 | 目标 | 动作 |
|---|---|---|
| `Chained/*``InterLock/*``Scheduler/*` 逻辑 | Core | 移动(导航无关) |
| `DeliveryViewer/LoopViewer/TrafficInterlockViewer`(窗体) | Core(Ui) | 迁UICycleGUI/Web |
### 4.4 充电(`Charge/` `ChargeStationType/`
| 现状 | 目标 | 动作 | 说明 |
|---|---|---|---|
| `AbstractChargeLogicMission``StandardChargeMission` | Core | 移动 | 充电逻辑 |
| `ChargeStation*`/`ChargeStrategy*`/`Alarm*`/`Communication*`(服务) | Core | 移动 | 充电管理/服务 |
| 各 `Charge/*Form`(窗体) | Core(Ui) | 迁UI | CycleGUI/Web |
| `ChargeStationType/AbstractChargeStation.cs` | Core | 移动 | 抽象 + 注册契约 |
| `ChargeStationType/{FL,MuXing,PCB}ChargeStation.cs` | **`Devices.Charge`** | 拆分 | 厂商驱动,独立热插拔 dll |
### 4.5 扩展设备(`ExtendDevice/`
| 现状 | 目标 | 动作 | 说明 |
|---|---|---|---|
| `Door/BasicDoorController``DoorMission``DoorModel``DoorTypeAttribute` | Core(框架) | 移动 | 门控框架 + 注册契约 |
| `Door/ModbusDoorController` | **`Devices.Door`** | 拆分 | Modbus 驱动,独立热插拔 |
| `Door/DoorManager/DoorMonitor`(窗体) | Core(Ui)/Devices.Door(Ui) | 迁UI | CycleGUI |
| `ButtonBox/BasicButtonBox``ButtonMission``ButtonBoxModel` | Core(框架) | 移动 | 按钮盒框架 |
| `ButtonBox/LeegButtonBox`(`leegKeys-sdk`)、`AzowieButtonBox` | **`Devices.ButtonBox`** | 拆分 | 厂商驱动,`leegKeys-sdk` 随驱动走 |
| `ButtonBox/ButtonBoxManager`(窗体) | 对应 dll(Ui) | 迁UI | CycleGUI |
### 4.6 公共 / 契约 / 模型 / 基础设施
| 现状 | 目标 | 动作 | 说明 |
|---|---|---|---|
| `Commons.cs::Commons` | Core | 移动 | 解除对 `DummyCar` 硬引用(`GetVehicleStatus` |
| `Commons.cs::CustomOperationsBeforeLoading` | 各可激活 dll 各一份 | 复制/分发 | `MessageBox` 死锁提醒改 CycleGUI 弹窗 |
| `Commons.cs::NoReflectionApi`/`ReflectionApiWithParameter` | SimpleCore 或 Core | 待复核 | 多 dll 共用建议下沉 SimpleCore |
| `Heuristic.cs` | Core | 移动 | 启发式(宿主反射注册) |
| `LadderLogic.cs` | Core | 移动 | 防抖/梯形逻辑 |
| `StandardCADTool.cs`(多数 `CADTool`) | Core | 移动 | 地图编辑工具 |
| `StandardCADTool.cs::SyncQrMap` | QrCode | 拆分 | 二维码地图下发 |
| `Model/Map.cs::Map/ArcHelper` | Core | 移动 | 地图序列化 |
| `Model/Map.cs::LidarMap` | Laser | 拆分 | SLAM 栅格图 |
| `Model/*`(其余) | Core | 移动 | 数据模型 |
| `Utils/*``TCP/*``CommonTools/*` | Core | 移动 | 基础设施 |
| `FactoryTest.cs` | — | **删除** | 评审确认 |
| 根 `MultiWheelLifterCar.cs`、根 `SongLingDeliveryViewer.Designer.cs` | — | **删除** | 死/残留 |
### 4.7 老 WebApi`WebApi.cs`)整理与迁移索引
**本版处置**:通用端点整理为 `WebApi.Core.cs` 暂留 Core 并标 deprecated;二维码/激光端点随导航 dll;**后期整体删除**,前端改用 SimpleLite 接口。下表为废弃迁移索引(老 Nancy → SimpleLite EmbedIO,依据 MIGU-API.md):
| 老端点(`WebApi.cs` | 行号 | SimpleLite 替代(`/api/sl/projection/...` |
|---|---|---|
| `car_reflection/mission_reflection get_type/methods/fields/execute` | 191537 | `reflection/methods/*``/fields/*``/execute/*``/bundle/*` |
| `car/getAllCars``api/agv/list` | 1047、2095 | `projection/cars` |
| `task/getTask` | 1099 | `projection/missions` |
| `map/getMap` | 995 | `projection/sites`+`/tracks`、或 `map-edit` |
| `car/goSite` | 1070 | `reflection/car/{id}/goto-site` |
| `car/reset/repair/blown/ForceStop/ReStart/...` | 767+ | `reflection/execute/{kind}/{id}/{method}``[MethodMember]` |
| `car/createTask/carTask/cancelTask` | 542/597/900 | `reflection/execute` + `projection/deliveries/*` |
| `set{Charging,Envelope,TrafficControl,PlanRules}Setting` | 1680+ | `reflection/fields/{kind}/{id}/{field}`(写字段) |
| `api/CreateSite` | 2055 | `map-edit/objects/site` |
| `api/QrMap`(二维码) | 2050 | 暂随 QrCode dllSimpleLite 侧待新增(无直接对应) |
| `map/getLidarMap`(激光) | 1021 | 暂随 Laser dllSimpleLite 侧待新增(无直接对应) |
> 注:二维码地图下发、激光 SLAM 取图在 SimpleLite 现有 MIGU-API 中**无直接对应**,迁移时需在 SimpleLite/场景插件侧补接口,故这两块随导航 dll 先行保留。
---
## 5. "抽离标准功能"清单(去重与沉淀)
1. **统一磁导航循迹器**`AllCarMagTrackCoder` + `MagTrackCoder` → 唯一 `StandardScene.Magnetic.MagneticTrackCoder`(参数化 fields)。
2. **车型基类 `StandardCarBase`(Core)**:上提 `newReset/newTrafficReset``SetDisplayInfo``Mstsc``EmergencyStop/Release``ResetClumsy``GetCarStatus` 默认实现。
3. **通用 Coder 模板集(Core/Coders)**:沉淀避障/IO/纠偏/避障尺寸等重复 `[TemplateTrackCoderSettings]`
4. **导航能力抽象 `INavigationProfile`**:每个导航 dll 实现一个 Profile(声明 `NavKind` + 提供的 coder/字段语义),Core/宿主反射收集。
5. **`Commons` 去重**:合并 `GetCarStatus``GetVehicleStatus` 去除对 `DummyCar` 的硬编码(改标记接口)。
6. **设备注册标准化**:充电桩/门/按钮盒统一特性注册,驱动 dll 即插即用 + 热插拔。
7. **UI 标准化**:原 WinForms 窗体统一迁 CycleGUI 面板(沉淀少量通用面板基类)。
---
## 6. 命名空间与依赖治理
- **宿主/命名空间迁移**`SimpleComposer.RCS`/`SimpleComposer.UI``SimpleLite.RCS`/对应(以内核改造为准,另一会话进行中);引用 `SimpleComposer.exe``SimpleLite` 程序集 + `SimpleCore` 契约。
- **命名空间收敛**`DummyCar``AMRScene1``StandardScene.Core.Cars.Sim`
- **去 WinForms**:移除 `System.Windows.Forms` 引用,窗体迁 CycleGUI/Web`MessageBox` 改 CycleGUI 弹窗。
- **反向依赖治理**`Commons.GetVehicleStatus``DummyCar``ArmCar``VDA5050SiteField`;二维码相关集中 QrCode dll,Core 仅留中立扩展点。
- **三方依赖随归属**`MQTTnet`→VDA5050`leegKeys-sdk`→ButtonBox 驱动;`EasyModbusTCP/IoTClient`→Door/Charge 驱动或 Core 工具;`Nancy`→(暂留的 WebApi.Core,验证 net8 兼容或对齐 SimpleLite 的 Nancy 2.0);`Jint`→含 DummyCar 仿真的 Core。
---
## 7. 关键技术难点与对策
### 7.1 难点①:TrackCoder 由"编译期特性"改为"运行期注册"
- 现状:coder 通过特性硬绑定车型类型。
- 目标:导航 dll 不改 Core 车型源码即可为车型补 coder。
- 对策:① **内核扩展(推荐)**——`SimpleCore` 增 coder 注册表,导航 dll 在 `INavigationProfile.OnActivate` 注册/卸载时移除(契合 `/plugins` 热插拔);② 车型留占位、导航 dll 实现委派;③ **兜底**——Core 内置全量 coder,导航 dll 只承载 API/地图/字段/清单。
- **行动项**:与正在改内核引用的会话同步,确认是否纳入注册表 API。
### 7.2 难点②:net4.8 → net8.0 迁移(换宿主 + 去 WinForms
- 宿主:引用 `SimpleComposer.exe`(net4.8) → `SimpleLite`/`SimpleCore`(net8)`SimpleComposer` 独有类型在内核侧补齐/下沉(与另一会话协作)。
- **去 WinForms(重点)**:所有窗体迁 CycleGUISimpleLite 立即模式 UI)或平台 Web;`MessageBox`→CycleGUI 弹窗/平台通知。工作量集中在 `Charge/*Form``Delivery/Loop/TrafficInterlock Viewer``VehicleMonitor``Door/ButtonBox` 管理窗体、`VDACar/TextViewer`
- 三方库 net8 验证:`Nancy(1.4.5)`(暂留 WebApi,验证或升 2.0)、`MQTTnet/EasyModbusTCP/IoTClient/Jint/Newtonsoft/DocumentFormat.OpenXml`
- Fody/`LessokajiWeaver`:与内核一致(注意上游 §13.2 环境约束)。
### 7.3 难点③:插件钩子与多 dll 初始化
- `CustomOperationsBeforeLoading.Set()` 宿主按 dll 反射调用:拆分后每个可激活 dll 各保留一份;用 `INavigationProfile.OnActivate` 做导航 dll 自初始化,避免重复注册全局回调。
### 7.4 难点④:设备/导航 dll 热插拔(collectible 卸载)
- 配合 SimpleLite `/plugins/reload``/plugins/{name}/unload``/scenes/apply`dll 须可被 collectible ALC 干净卸载(卸载前无存活 `Car/Mission` 实例),`OnDeactivate` 清理注册的 coder/设备/回调/MQTT 连接/TCP 客户端。
### 7.5 难点⑤:老 WebApi 暂留与最终下线
- `WebApi.Core`(Nancy) 暂留 Core 仅为过渡;新功能一律走 SimpleLite EmbedIO。按 §4.7 索引逐步迁移,迁完即删;二维码/激光取图需先在 SimpleLite/场景插件侧补接口。
---
## 8. 分阶段实施计划(务实路线)
> 原则:每阶段都能编译、能加载、可回退。
### C0 · 准备与对齐(低风险,先做)
- 删除:`FactoryTest.cs`、根 `SongLingDeliveryViewer.Designer.cs`、根 `MultiWheelLifterCar.cs``UselessCar`
- 去重沉淀(§5):统一 `MagTrackCoder``GetCarStatus`;提取 `StandardCarBase`
- 命名空间收敛 `AMRScene1`→Core。
- 与内核会话对齐:`SimpleLite`/`SimpleCore` 引用与命名空间、coder 注册表(§7.1)、导航契约(上游 Phase A 已就绪)。
- 验收:编译通过、行为不变。
### C1 · Core 基座 net8.0 化(换宿主 + 去 WinForms 闭环)
- 新建 `StandardScene.Core`(net8.0),迁入导航无关全部内容;引用切到 `SimpleLite`/`SimpleCore`
- **去 WinForms**:窗体迁 CycleGUI`MessageBox`→CycleGUI。
- 整理老 `WebApi``WebApi.Core`(deprecated, 暂留)。
- coder 先用兜底(§7.1 方案③)保证不回归。
- 验收:`StandardScene.Core.dll` 被 SimpleLite 加载、跑通搬运/充电/交管。
### C2 · 抽离导航能力 dll
- `Magnetic`(唯一 `MagneticTrackCoder`/ `QrCode``QrTrackCoder`+`SyncQrMap`+`QrMap`/ `Laser``LidarMap`+`getLidarMap`),各带 `scene.json`
- 按 §7.1 选定方案把 coder 接到车型。
- 验收:仅激活某导航时对应能力可用,其余不加载。
### C3 · 设备驱动 dll 化(必做,热插拔)
- `Devices.Charge`(FL/MuXing/PCB)、`Devices.Door`(Modbus)、`Devices.ButtonBox`(Leeg/Azowie)`leegKeys-sdk` 随驱动。
- 验证 `/plugins` reload/unload 热插拔;`OnDeactivate` 清理连接。
- 验收:设备驱动可独立热加载/卸载。
### C4 · VDA5050 协议 dll
- `Protocol.VDA5050`(整 `VDACar/` 迁出,含 MQTT);解 `ArmCar↔VDA5050SiteField`
- 验收:激活后 VDA5050 车可用、可卸载。
### C5 · 联调、WebApi 迁移与文档
- 三导航 + 设备 + 协议组合联调;对接 `/scenes/apply` + `active-scenes.json`
- 按 §4.7 把可迁的 WebApi 端点切到 SimpleLite,逐步删 `WebApi.Core`
- 更新本文件 §11 进度 + `scene.json` 实际清单 + `README/DEVELOPMENT_GUIDE`
---
## 9. 插件清单契约(`scene.json`,对接上游 §5.5 与 SimpleLite `/scenes`
```json
{
"id": "scene.magnetic",
"displayName": "磁导航场景",
"navKind": "Magnetic",
"assembly": "StandardScene.Magnetic.dll",
"requiresCore": "StandardScene.Core.dll",
"provides": { "trackCoders": ["MagneticTrackCoder"], "carTypeBindings": ["*"] }
}
```
- 平台「配置向导」→ `WizardController` 写配置 → 调 SimpleLite `POST /api/sl/projection/scenes/apply`(写 `active-scenes.json` + 增量 reload)。
- 数据契约:`data/config-deployment.json`(平台)/ `plugins/active-scenes.json`(内核)/ `plugins/<dll>.scene.json`(插件)。
---
## 10. 风险、待确认与验收口径
### 已确认(v2
- 宿主 = SimpleLite;老 SimpleComposer 废弃。
- 目标框架 = `net8.0`(去 WinFormsUI 迁 CycleGUI/Web)。
- 设备驱动 = 独立 dll + 热插拔。
- `FactoryTest`、松灵残留 = 删除。
- `WebApi.cs` = 整理后暂留 Core、后期废弃迁 SimpleLite。
### 待确认
1. **coder 注册表**:内核是否纳入"运行期把 TrackCoder 注册到车型"的 API(否则 C2 用兜底方案③)。
2. **UI 迁移范围与节奏**:窗体一次性迁 CycleGUI,还是按 dll 分批;是否部分仅保留平台 Web 入口。
3. **VDA5050** 独立 dll 确认(推荐独立)。
4. **二维码地图下发 / 激光 SLAM 取图**SimpleLite 侧补接口的归属与时间点。
5. **车型↔导航映射**:是否存在车型仅支持单一导航的硬约束。
### 验收口径(每阶段通用)
- 编译 0 错误;搬运/环线/充电/交管不回归。
- 选择性加载 + 热插拔:激活集合内能力可用,未激活不加载、可干净卸载。
- 反射 APISimpleLite `/reflection`)、车型/面板随已激活 dll 自然收敛。
---
## 11. 实施进度记忆(跨会话持续更新)
> 状态:⬜ 未开始 / 🟦 进行中 / ✅ 完成 / ⏸ 暂缓。
> **最近更新:会话1(续3,2026-06-09)——设备三 dll 合并为单一 `StandardScene.Devices` + `ChangeAvoidanceParam` 去重(方案 B),全解 `dotnet build` 0 错误。**
### 11.0 当前代码现状(重要:已领先早期文档)
会话1 接手时发现**代码已被先前会话推进**,与 v2 文档/会话14交接摘要描述的「net4.8 单体、未动代码」**不一致**。以 `StandardScene.csproj` 实际为准:
| 项 | 早期文档记述 | **当前实际** |
|---|---|---|
| 目标框架 | net4.8 | **`net8.0-windows`**(仍 `UseWindowsForms=true`,过渡态,**尚未**去 WinForms 到纯 net8.0 |
| 宿主/契约引用 | SimpleComposer.exe + RefSimpleCore | **已切 `SimpleLite.dll` + `SimpleCore.dll`(netstandard2.0)** |
| Nancy | 1.4.5 | **已对齐 `2.0.0`** |
| 死代码 | 在仓库 | csproj 已 `Compile Remove`,会话1 已物理删除 |
| 命名空间 | SimpleComposer.RCS | 车型 using 已是 `SimpleLite.RCS`(内核改造会话已推进) |
**可编译基线**`dotnet build`net8.0-windowsdotnet SDK 10.0.300= **0 错误 / 47 警告**(均无害:重复 using、隐藏成员 CS0108、未用变量、`Thread.Abort` SYSLIB0006、CS4014 未 await 等)。
### 11.1 步骤状态
| 步骤 | 内容 | 状态 | 说明 |
|---|---|---|---|
| P0 | 精读现状 + 产出拆分计划 v1 | ✅ | 逐文件精读 |
| P0.1 | 按评审反馈更新 v2 | ✅ | |
| **路线决策** | 评审定 **路线乙**:先「纯搬运不改逻辑」的结构拆分,去重在新结构里从容做 | ✅ | 会话1 用户拍板 |
| **C0-a** | 物理删除死代码 + 清理 csproj | ✅ | 见 §11.3 |
| **C0-b** | 抽离 **4 个通用(导航无关) coder** 并在 4 车型切换 | ✅ | 见 §11.3;编译 0 错误 |
| C0-c | 合并两份磁循迹器为唯一 `MagneticTrackCoder` | ✅ | 用户定:采用含 `track.Speed``NaiveMagGo`;MWL 旧类已删、引用改向;编译 0 错误 |
| C0-d | `ChangeAvoidanceParam` 去重 | ✅ | 方案 B:4 参 flag 版 `AvoidanceParamCoder`(MWL+MultiVehicle) + 2 参 L,W 版 `AvoidanceParamLWCoder`(Kiva+Forklift);见 §11.4-2 |
| C0-e | 提取 `StandardCarBase`newReset/Mstsc/GetCarStatus 等上提)| ⬜ | 未启动 |
| C0-f | `AMRScene1` 命名空间收敛 | ⬜ | 建议并入 C1 建 Core 工程时一起做 |
| 路线乙·1 | 工程迁入 `StandardScene.Core/` + 重写 sln(纯搬运) | ✅ | 编译 0 错;AssemblyName 仍=`StandardScene`,对外 dll 名不变 |
| C1 | 去 WinForms + WebApi.Core 整理 | ⏸ | 用户暂缓(窗体后续迁 migu 平台);过渡期各工程暂 `net8.0-windows` |
| C2 | Magnetic/QrCode/Laser 三导航 dll | ⏸ | 受阻于内核 coder 注册表(§11.4-4) + 用户将自行重构 coder |
| **C3** | 设备驱动 dll 化(Charge/Door/ButtonBox,热插拔) | ✅ | 见 §11.3-E3;**合为单一 `StandardScene.Devices`**(用户定,不分多个),编译 0 错、scene.json 产出 |
| **C4** | VDA5050 协议 dll | ✅ | 见 §11.3-E2`VDACar/` 整迁出、`VDA5050SiteField` 下沉 Core |
| C5 | 联调 + WebApi 迁移 SimpleLite + 文档收尾 | ⬜ | 含卫星 dll→宿主 `plugins/` 部署 + 真机联调(见 §11.4-5) |
### 11.2 关键决策记录
- **路线乙(会话1 确认)**:结构拆分优先、纯搬运不改逻辑;去重沉淀在新结构内做。理由:本环境无法跑真实 AGV 回归,纯搬运行为风险低、编译即可保障。
- 导航与车型正交;导航 coder 外置为可插拔(运行期注册,内核配合;**当前用兜底=Core/单体内置 coder**,用户要求"先抽离合适的通用 coder")。
- 激光避障(LidarArea)留 Core,仅 SLAM 地图(LidarMap/getLidarMap)进 Laser。
- 设备驱动单列 `Devices.*` 独立 dll + 热插拔(评审确认)。
- 宿主 SimpleComposer→SimpleLite;框架统一 net8.0UI 去 WinForms 迁 CycleGUI/Web(评审确认)。
- `FactoryTest`、松灵残留删除(评审确认,会话1 已执行)。
-`WebApi.cs`(Nancy) 暂留 Core、标 deprecated,后期迁 SimpleLite EmbedIO,迁移索引见 §4.7(评审确认)。
### 11.3 会话1 已落地改动明细(2026-06-09
**A. C0 死代码物理删除**(编译范围不变,0 错误)
-`FactoryTest.cs``[MissionType]` 展会演示进程,反射注册,无其它引用)
- 删 根 `MultiWheelLifterCar.cs`(与 `CarTypes/MultiWheelLifterCar.cs` 重名死文件)
- 删 根 `SongLingDeliveryViewer.Designer.cs`(松灵残留,无主文件)
-`CarTypes/UselessCar.cs``[CarType]` 已注释、未注册)
- `csproj`:移除上述 3 条 `Compile Remove`**保留** `Chained\AbstractChainedDeliveryMission.cs` 的 Remove(孤立未编译旧版本,去留待后续核对)
**B. 抽离通用(导航无关) coder** —— 新增 `Coders/CommonTrackCoders.cs`(命名空间 `StandardScene.Coders`
- 基类 `CommonTemplateTrackCoder : ITrackCoder`:内部复用内核 `ProgramCoderHelper.PrepareTrackEngine` + Topaz 求值,`useVerb`/`templateString` 与原模板逐字一致;统一用 `BasicXxxFields`(这些 coder 仅引用 Basic 字段,等价)。priority 由车型 `[ProgramTrackCoderSettings]` 指定。
- 4 个通用 coder
- `LidarAreaSwitchCoder`(避障,`track.LidarArea != -2``SwitchLidarArea`
- `AvoidanceDistanceCoder`(无 useVerb → `ChangeAvoidanceDistance(StopDistance,SlowDistance)`
- `IoAreaSwitchCoder``track.IOArea != -1``SwitchIoArea`
- `TrackingErrThreshCoder``BiasAlarmThresh>0||DthAlarmThresh>0``ChangeTrackingErrThresh`
- 4 车型已把对应内联 `[TemplateTrackCoderSettings]` 删除,改为 `[ProgramTrackCoderSettings]` 引用(保留各自原 priority):
| 车型 | LidarArea | AvoidanceDistance | IoArea | TrackingErrThresh |
|---|---|---|---|---|
| `Kiva` | 17 | 20 | 20 | 20 |
| `MultiWheelLifterCar` | 27 | 20 | 20 | 20 |
| `MultiVehicleCar` | 27 | 20 | 20 | 20 |
| `Forklift` | 20 | —(原无) | 20 | 20 |
- 各车型加 `using StandardScene.Coders;`
- **验证**:每步 `dotnet build` 均 0 错误(Kiva 单切先验范式,再批量推 MWL/MultiVehicle/Forklift)。
**C. 仍保留为内联 Template / 程序 coder(本次未动)**
- 磁程序 coder`Kiva.AllCarMagTrackCoder``MultiWheelLifterCar.MagTrackCoder`(待 C0-c 合并)
- `ChangeAvoidanceParam`(三变体,待 C0-d
- `Kiva.KivaCarTrackCoder`(转弯)、`CalibrateWheelEncoder`(仅 Kiva)
- 二维码 `QrGo`(导航专用,归 QrCode dll);各车型取放货/钻车/夹抱/TireFollowing 等(车型专用)
**D. 会话1(续)去重落地**(编译 0 错误 / 0 lint
- **磁循迹器合并(C0-c**`Kiva.AllCarMagTrackCoder` 重命名为唯一 `MagneticTrackCoder`(含 `${track.Speed}``NaiveMagGo`,用户确认);`MultiWheelLifterCar.MagTrackCoder` 整类删除,其 `[ProgramTrackCoderSettings(priority=19)]` 改向 `MagneticTrackCoder`。(暂置 `Kiva.cs``StandardScene.CarTypes` 命名空间,C2 抽 Magnetic dll 时物理迁出。)
- **避障 4 参对合并(C0-d 部分)**:新增 `Coders.AvoidanceParamCoder``CommonTemplateTrackCoder` 子类,覆写站点字段袋为含 `ChangeAvoidanceParam` 标志位的 `AvoidanceParamSiteFields`),useVerb/模板与原 `MWL`/`MultiVehicle` 逐字一致;两车型删内联 4 参模板、改 `[ProgramTrackCoderSettings(priority=20)]` 引用。基类新增可覆写 `SiteFieldsType` 钩子(默认 `BasicSiteFields`)。
**E. 会话1(续2)结构性拆分落地**(路线乙·结构拆分;全解决方案 `dotnet build` 0 错误 / 45 无害警告)
*E1. 工程迁入 `StandardScene.Core/`(纯搬运)*
- 原单体整体迁入子目录 `StandardScene.Core/``StandardScene.csproj``StandardScene.Core.csproj`**AssemblyName 仍=`StandardScene`**,对外 dll 名不变);重写 `StandardScene.sln`
- 新增 `Properties/InternalsVisibleTo.cs`:对 4 卫星程序集开放 internal(`Protocol.VDA5050`/`Devices.Charge`/`Devices.Door`/`Devices.ButtonBox`),使卫星以"纯搬运"访问 Core internal,免去大量 internal→public 侵入式改动。
*E2. `StandardScene.Protocol.VDA5050`C4*
- `CarTypes/VDACar/`10 文件)整迁至新工程;`scene.json`(provides VDA5050Car)csproj 引 Core(ProjectReference)+SimpleLite/SimpleCore/CommonUsage/Topaz/Weaver + MQTTnet/Nancy/Jint/Newtonsoft。
- 解耦:`VDA5050SiteField``VDACar/VDA5050Car.cs` **下沉**至 Core `CarTypes/ArmCar.cs``ArmCar` 留 Core 且引用它,不能反依赖 VDA dll)。
*E3. `StandardScene.Devices`C3,用户选 A**门/充电桩/按钮盒合并为单一 dll**,用户定不分多个;内部按 `Door/``Charge/``ButtonBox/` 子目录组织,Core 的 IVT 仅 `StandardScene.Devices` 一项)*
- 搬出 6 具体驱动(**命名空间不变**,仍 `StandardScene.ExtendDevice.*` / `StandardScene.ChargeStationType`,以满足发现谓词 `t.Namespace==基类.Namespace`):
- Door`ModbusDoorController`(基类 `BasicDoorController`+`[DoorType]` 留 Core
- Charge`FL/PCB/MuXingChargeStation`(基类 `AbstractChargeStation`+`ChargeUdpService`/`StandardChargeMission` 留 Core
- ButtonBox`Leeg/AzowieButtonBox`(基类 `BasicButtonBox`+`ButtonMission`/`ButtonBoxManager` 留 Core;该 dll 额外引 `Ref/leegKeys-sdk.dll`
- **行为保持解耦(2 处下转型→基类虚方法)**:
- `ChargeUdpService``if(cs is PCBChargeStation s) s.IndexReceive=msg[1]``cs.OnUdpMessage(msg)``AbstractChargeStation` 空实现、`PCB` override)。
- `ButtonMission``if(bb is AzowieButtonBox a) a.ClearButtonRegister(i)``bb.ClearButtonRegister(i)``BasicButtonBox` 空实现、`Azowie` 改 override)。
- **类型发现改跨程序集(5 处,关键)**:原 Core 限定扫描(`Type.GetType(简单名)` / `typeof(基类).Assembly.GetTypes()` / `Assembly.GetExecutingAssembly().GetTypes()`)只在 Core 内找类型,驱动外移后**运行期将找不到**。统一改用内核公开的 `SimpleLite.Utils.UiTypeDiscovery.AllTypes()``AppDomain.GetAssemblies()` 全域 + 内置 `ReflectionTypeLoadException` 安全枚举),谓词不变 → 今天在 Core 内仍找到原类型(**行为等价**)、外移后亦能发现。涉及 `StandardChargeMission` / `DoorMission` / `DoorManager` / `ButtonMission` / `ButtonBoxManager`
- 关键依据:SimpleLite 自身类型发现即 `UiTypeDiscovery`(AppDomain 全域) + `PluginManager`(从 `./plugins/*.dll` 以 collectible ALC 热加载)→**卫星 dll 路线运行期成立**(同时回证 VDA5050Car 可被发现)。
### 11.4 待确认 / 阻塞项(影响 C0 收尾与 C2)
1. ~~**磁 `NaiveMagGo` 参数差异**~~ **【会话1 已决】**:用户定采用含 `${track.Speed}` 的版本(Kiva 版)。已合并为唯一 `MagneticTrackCoder``MultiWheelLifterCar.MagTrackCoder` 删除并改向引用。编译 0 错误。(普通 `MagGo` 两份原本一致;合并后磁逻辑全平台统一。)
2. ~~**`ChangeAvoidanceParam` 统一方式**~~ **【会话1续3 已决:方案 B】**:用户选 B。落地=4 参 flag 版 `AvoidanceParamCoder`(MWL+MultiVehicle) + 新增 2 参 L,W 版 `AvoidanceParamLWCoder`(Kiva+Forklift,触发统一取 `dst.CarLength!=-1 && dst.CarWidth!=-1`);两车型内联 `[TemplateTrackCoderSettings]``[ProgramTrackCoderSettings(priority=20)]` 引用。Forklift 行为不变;Kiva 原无条件→统一后未配置长宽(-1)时不再下发 `(-1,-1)`(预期内安全收敛)。编译 0 错。原分析留档如下:
- 现状:`Kiva`=无条件/2 参;`Forklift`=`L≠-1&&W≠-1`/2 参;`MWL`/`MultiVehicle`=`ChangeAvoidanceParam==true`/4 参(含中心点)。
- 已落地(零行为变更):把**逐字相同**的 `MWL`+`MultiVehicle` 4 参对合并为 `Coders.AvoidanceParamCoder`
- 关键事实:`CarLength/CarWidth/CarCenterX/CarCenterY` 均已在 `BasicSiteFields` 定义(中心点默认 0),故 4 参模板对各车型都可解析编译;差异只剩「触发条件 + 参数个数」。
- 选项(已在会话中给用户):**A**=真·单 coder 分支(flag→4 参 / 否则 L,W 有效→2 参;副作用:Kiva 未配置站点不再发 `(-1,-1)` + MWL 设了 L,W 但 flag=false 会新发 2 参);**B**=两 coder4 参 flag 版+2 参 L,W 版;仅 Kiva `(-1,-1)` 行为差,无 MWL 污染);**C**=只留已合并的同构对,Kiva/Forklift 维持内联(零变更)。**建议 B**(避障涉安全,最小行为差)。
3. ~~**去 WinForms 迁移策略**~~ **【会话1 暂定】**:用户"暂不/去掉",本阶段不动窗体,留待 C1 专门处理。
4. ~~**内核 coder 运行期注册表**~~ **【会话1 已核查】**:当前内核**无插件化 coder 注册表**。`SegmentPlan.SetCoders()` 仅硬接 `TemplateCoderSet`+`ProgramCoderSet` 两套,均按**车型类特性**(`[*TrackCoderSettings]`)反射、在**同程序集**内 `Activator.CreateInstance`(无参构造)实例化——无外部 dll 扫描/动态注册 API。
- 推论①:本次抽出的 `StandardScene.Coders.*` 程序 coder **能被正确加载**(车型特性 `typeof()` 引用 + 无参构造,命名空间无关),故 C0-b/c/d 成立。
- 推论②:**C2「导航 coder 拆独立可热插拔 dll」受阻**——需内核侧(另一会话)补「运行期 coder 注册 / 插件程序集扫描」插桩;在此之前**继续兜底=coder 留在 Core 同程序集**、由车型特性引用。
5. ~~**设备驱动外移后运行期发现**~~ **【会话1续2 已解】**StandardScene 自有的设备类型发现原为 **Core 限定扫描**(与内核 `UiTypeDiscovery` 全域发现不一致),直接外移会断。已把 5 处统一改 `UiTypeDiscovery.AllTypes()`(行为等价、跨程序集)。**遗留验证项(运行期,归 C5)**:卫星 dll 须被 SimpleLite 实际加载入 AppDomain`PluginManager``./plugins/` 加载)发现方生效——需将 `StandardScene.Devices.*.dll`+`scene.json` 部署到宿主 `plugins/` 并做一次真机/集成联调。与 coder(§11.4-4) 不同:设备发现码在**本仓库**、可自主修改,故 C3 不受内核阻塞。
### 11.5 下一会话推荐起手式
1. 读 §11.0(代码现状)+ §11.3(已落地,含 **E. 结构拆分**+ §11.4(待确认/已解)。
2. **结构拆分现状**`StandardScene.Core` + 卫星 `Protocol.VDA5050``Devices.{Door,Charge,ButtonBox}` 已建并全解 0 错;导航 dll(C2) 待用户重构 coder + 内核注册表后再动。
3. 待用户就 §11.4-2 拍板:`ChangeAvoidanceParam` 收尾(建议 B)。coder 整体重构由用户主导。
4. C5 验证项:把 `StandardScene.Devices.*.dll`+`scene.json` 部署到宿主 `plugins/`,真机/集成验证设备与 VDA 车型的**运行期发现**(§11.4-5)。
5. 校验手段:每步 `dotnet build StandardScene.sln`net8.0-windows)须保持 0 错误;真机回归留待有环境时。
### 11.6 变更日志
| 时间 | 步骤 | 改动 | 备注 |
|---|---|---|---|
| 初始 | P0 | 新增 `StandardScene拆分计划.md`(v1) | 现状精读 + 归属矩阵 + 抽离清单 + 技术难点 + 分阶段 |
| v2 | P0.1 | 全文更新 | 宿主 SimpleLite、框架 net8.0、去 WinForms、设备独立 dll、删除项、WebApi 暂留+迁移索引 |
| 会话1 | C0-a | 物理删除 4 个死代码文件 + 清理 csproj | 编译 0 错误 |
| 会话1 | C0-b | 新增 `Coders/CommonTrackCoders.cs`4 通用 coder);Kiva/MWL/MultiVehicle/Forklift 切换为 ProgramTrackCoder 引用 | 编译 0 错误;NaiveMag/AvoidanceParam 留待确认 |
| 会话1续 | C0-c | 磁循迹器去重:`AllCarMagTrackCoder`→唯一 `MagneticTrackCoder`(含 `track.Speed`);删 `MagTrackCoder` 改向引用 | 用户确认 track.Speed 版;编译 0 错误 |
| 会话1续 | C0-d | 避障同构对去重:`MWL`+`MultiVehicle` 4 参模板→`AvoidanceParamCoder`;基类加 `SiteFieldsType` 钩子 | 零行为变更;Kiva/Forklift 并法待定(§11.4-2) |
| 会话1续 | 核查 | 内核 coder 注册机制核查:无插件注册表,仅车型特性+同程序集反射 | 见 §11.4-4;C2 需内核插桩 |
| 会话1续2 | 路线乙·1 | 工程迁入 `StandardScene.Core/``.csproj``StandardScene.Core.csproj`、重写 `.sln`、加 `Properties/InternalsVisibleTo.cs`(4 卫星) | 纯搬运;编译 0 错 |
| 会话1续2 | C4 | 拆 `Protocol.VDA5050``CarTypes/VDACar/`(10 文件)整迁出;`VDA5050SiteField` 下沉 `ArmCar.cs` 解耦;scene.json | 编译 0 错 |
| 会话1续2 | C3 | 拆 `Devices.{Door,Charge,ButtonBox}`6 驱动外移;2 处 `is 具体类`→基类虚方法;5 处类型发现→`UiTypeDiscovery.AllTypes()` 跨程序集 | 行为等价;全解编译 0 错、3 dll+scene.json 产出 |
| 会话1续3 | C3 | 三 `Devices.*` **合并为单一 `StandardScene.Devices`**(内部 Door/Charge/ButtonBox 子目录;IVT 3→1;删旧 3 工程、重写 sln) | 用户定"不分多个";编译 0 错、单 dll+scene.json 产出 |
| 会话1续3 | C0-d | `ChangeAvoidanceParam` 去重收尾(方案 B):新增 2 参 `AvoidanceParamLWCoder`Kiva/Forklift 内联模板→`[ProgramTrackCoderSettings(priority=20)]` 引用 | 编译 0 错;Forklift 不变、Kiva `(-1,-1)` 安全收敛 |
---
*附:本计划引用的类/文件/行号均来自当前工程 `E:\Work\Core\Simple-FR\StandardSence` 实际代码走查;SimpleLite 接口依据 `E:\Work\Core\Simple-FR\Simple\SimpleLite\Docs\MIGU-API.md` 与 `SimpleLite.csproj`net8.0 / CycleGUI / EmbedIO)。*