2026-05-29 18:16:34 +08:00
|
|
|
|
# 平台 v3 重构 — 阶段 0~6 实际改动
|
|
|
|
|
|
|
2026-08-26 17:46:52 +08:00
|
|
|
|
> 范围:把 Simple3 WebTerminal 由"全功能浮动 Panel"模式收敛到"纯 3D Canvas",所有 UI 改由 Vue 平台前端 (`frontends/apps/simple-platform-vue`) 接管;同时补齐反射 / 编辑 / 监控 / 编排 4 大业务面板与撤销栈、AI 生图、报警 SSE 等关键能力。
|
2026-05-29 18:16:34 +08:00
|
|
|
|
>
|
|
|
|
|
|
> 基线:上一份方案见 `ARCHITECTURE.md` v2/v3 章节;后续以本文件为准。
|
|
|
|
|
|
|
|
|
|
|
|
## 编译验证
|
|
|
|
|
|
|
2026-08-26 17:46:52 +08:00
|
|
|
|
- `dotnet build Simple3/Simple3.csproj` —— 0 警告 0 错误
|
2026-05-29 18:16:34 +08:00
|
|
|
|
- `dotnet build MiGu.Server/MiGu.Server.csproj` —— 0 警告 0 错误
|
|
|
|
|
|
- `build-platform-frontend.bat` —— vite build 46.5s,无 vue-tsc / ts 错误,robocopy /MIR 已同步 MiGu.Server/wwwroot
|
|
|
|
|
|
- 旧 `SimpleComposer` (WinForms) 在 v3 之外,不在本次构建目标里
|
|
|
|
|
|
- 旧 `HttpClientHelper` 提升 LangVersion=latest 修通
|
|
|
|
|
|
|
2026-08-26 17:46:52 +08:00
|
|
|
|
## 阶段 0:后端 Simple3 平台化(已完成)
|
2026-05-29 18:16:34 +08:00
|
|
|
|
|
|
|
|
|
|
### 新增文件
|
|
|
|
|
|
|
|
|
|
|
|
| 文件 | 作用 |
|
|
|
|
|
|
|------|------|
|
2026-08-26 17:46:52 +08:00
|
|
|
|
| `Simple3/Web/MapEditApiController.cs` | 写操作 8 路 API:create/delete/batch/copy-to/pick/dashboard/upload/ai-generate;阶段 6 又补:**project/save**、**project/load**、**project/current**、**sample-sites-along-track** |
|
|
|
|
|
|
| `Simple3/Web/ReflectionApiController.cs` | 只读 + execute API;listKinds / listObjects / methods-by-type / setField / getBundle / selection 等 |
|
|
|
|
|
|
| `Simple3/Web/ReflectionApiDtos.cs` | 反射 API DTO + 统一信封 `ReflectionEnvelope<T>` |
|
|
|
|
|
|
| `Simple3/Web/AiCompletionService.cs` | OpenAI Function Calling 调用 + map-generate 工具桥(真实 LLM,不再桩) |
|
|
|
|
|
|
| `Simple3/Web/AiConfigController.cs` | AI 服务配置(endpoint/apiKey/model/system prompt/temperature/maxTokens/timeout)读写 |
|
|
|
|
|
|
| `Simple3/Web/AlarmStreamService.cs` | 1s 周期 diff `car.status.enums.AlarmInfo`(语义与 `E:\Work\FRLD\StandardScene\Forklift.cs` 的 `Commons.GetCarStatus(this, "AlarmInfo")` 等价),变化时通过 SSE `alarm` 事件推送 raise/update/clear |
|
|
|
|
|
|
| `Simple3/Web/ProjectionStreamModule.cs` | 平台 SSE 总线,对外广播 `object-created` / `object-deleted` / `object-patched` / `object-batch-changed` / `alarm` / `pick-result` / `project-saved` / `project-loaded` |
|
|
|
|
|
|
| `Simple3/Web/PluginAssemblyScan.cs` | 反射扫描 plugins/*.dll,把 `MethodMember` 标注的方法 + Car/Mission/CarProgram/Site/Track 子类型暴露给反射 API |
|
2026-05-29 18:16:34 +08:00
|
|
|
|
|
|
|
|
|
|
### 修改文件
|
|
|
|
|
|
|
|
|
|
|
|
| 文件 | 关键改动 |
|
|
|
|
|
|
|------|----------|
|
2026-08-26 17:46:52 +08:00
|
|
|
|
| `Simple3/Startup.cs` | EntryPoint 第一步 `EnsureImguiIniFromEmbedded()`;启动 AlarmStreamService、ProjectionStreamModule、AiConfig 加载 |
|
|
|
|
|
|
| `Simple3/UI/SimpleUI.cs` | `CreateRemotePanelSetForTerminal` 检测 CanvasOnly 旗标:不创建 Workbench / Toolbar / BottomBar / CAD / Welcome;保留 SelectionAction、SceneInput、SceneDrawable、2DMapView |
|
|
|
|
|
|
| `Simple3/Workspace/WorkspaceWebUiContext.cs` | 增加 `IsCanvasOnly(terminal)` 旗标 + `/declareCanvasOnly` 注册器(与 `/declareEmbedUi` 互斥) |
|
|
|
|
|
|
| `Simple3/Web/ProjectionWebHost.cs` | `/declareCanvasOnly` 路由注册 |
|
|
|
|
|
|
| `Simple3/Web/ProjectionWebApiController.cs` | 现有 projection API 上挂 `selection-detail` SSE hook |
|
|
|
|
|
|
| `Simple3/UI/ComposerDockPanel.cs` | CanvasOnly 时 PrepareWelcomePanel 返回空 |
|
|
|
|
|
|
| `Simple3/Props/UIHelpers.cs` | 增加 `UI_Image` / `UI_Text` / `UI_Model` PropType。`UI_Model` 用于 CycleGUI 装饰物挂模型(obj/glb/gltf/cyclemodel) |
|
2026-05-29 18:16:34 +08:00
|
|
|
|
|
|
|
|
|
|
### 关键 API 路径
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
POST /projection/map-edit/objects/{kind} # site|track|bezier|arc|nurbs|image|text|model
|
|
|
|
|
|
DELETE /projection/map-edit/objects/{kind}/{id}
|
|
|
|
|
|
POST /projection/map-edit/objects/batch # create/delete/patch 混合
|
|
|
|
|
|
POST /projection/map-edit/objects/{kind}/{id}/fields/copy-to
|
|
|
|
|
|
POST /projection/map-edit/pick # 拾取会话
|
|
|
|
|
|
GET /projection/map-edit/dashboard/summary # KPI 聚合
|
|
|
|
|
|
POST /projection/map-edit/assets/upload # 图片/模型 base64
|
|
|
|
|
|
POST /projection/map-edit/ai/map-generate # 真实 LLM 生图
|
|
|
|
|
|
|
|
|
|
|
|
# 阶段 6 新增(本会话)
|
|
|
|
|
|
POST /projection/map-edit/project/save # body: { path?: string }
|
|
|
|
|
|
POST /projection/map-edit/project/load # body: { path: string }
|
|
|
|
|
|
GET /projection/map-edit/project/current
|
|
|
|
|
|
POST /projection/map-edit/objects/track/{id}/sample-sites
|
|
|
|
|
|
# body: { spacingMm, includeEndpoints?, layer? }
|
|
|
|
|
|
|
|
|
|
|
|
GET /projection/ai-config # 读 AI 服务配置
|
|
|
|
|
|
POST /projection/ai-config # 写 AI 服务配置
|
|
|
|
|
|
|
|
|
|
|
|
GET /projection/reflection/kinds | objects/{kind} | methods/{kind}/{id} | ...
|
|
|
|
|
|
SSE /projection/stream # 所有 SSE 事件
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 阶段 1:MapEditorView 四栏壳(已完成)
|
|
|
|
|
|
|
|
|
|
|
|
`frontends/apps/simple-platform-vue/src/views/admin/MapEditorView.vue` 完整重写为:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
┌─────────────────────────────────────────────────────┐
|
|
|
|
|
|
│ EditTopBar:项目 / 文件 / 编辑 / 视图 / 图层 / 对齐吸附 │
|
|
|
|
|
|
│ + 撤销/重做 + AI 生图 + 保存 │
|
|
|
|
|
|
├──────┬─────────────────────────┬───────────────────┤
|
|
|
|
|
|
│ Edit │ Workspace3D │ EditPropertyPanel │
|
|
|
|
|
|
│ Tool │ (canvas-only iframe) │ 对象/类型默认/图层 │
|
|
|
|
|
|
│ Rail │ │ │
|
|
|
|
|
|
├──────┴─────────────────────────┴───────────────────┤
|
|
|
|
|
|
│ EditStatusBar:选中 / 鼠标坐标 / 工具 / 吸附 / undo │
|
|
|
|
|
|
└─────────────────────────────────────────────────────┘
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 新增组件
|
|
|
|
|
|
|
|
|
|
|
|
- `components/map-editor/EditTopBar.vue` —— 6 个 dropdown 菜单(项目/文件/编辑/视图/图层/对齐吸附)+ 撤销重做按钮 + AI 生图入口 + 保存
|
|
|
|
|
|
- `components/map-editor/EditToolRail.vue` —— 6 组 CAD 工具按钮 + 吸附组(网格/对象/端点/中点 + 网格步长)
|
|
|
|
|
|
- `components/map-editor/EditPropertyPanel.vue` —— 3 Tab(对象 / 类型默认 / 图层),自动反射出 `getFields`,每行可改可保存;多选时统一字段写入;不一致字段显示「-」;执行 reflectionApi.execute 调任何 MethodMember
|
|
|
|
|
|
- `components/map-editor/EditStatusBar.vue` —— 状态栏
|
|
|
|
|
|
- `components/map-editor/AiGenerateDialog.vue` —— AI 生图对话框
|
|
|
|
|
|
|
|
|
|
|
|
### 反射 API 接入
|
|
|
|
|
|
|
|
|
|
|
|
- `api/mapEdit.ts` —— MapEditApiController 全 8+4 路 API 胶水(本会话补的 4 个:projectSave / projectLoad / projectCurrent / sampleSitesAlongTrack)
|
|
|
|
|
|
- `api/reflection.ts` —— ReflectionApiController 全套胶水(含 MOCK 离线 fallback)
|
|
|
|
|
|
|
|
|
|
|
|
## 阶段 2:对齐 / 批量生成 / 复制字段 / 类型默认 / 图层(已完成)
|
|
|
|
|
|
|
|
|
|
|
|
- `composables/useAlignment.ts` —— 11 种对齐模式:left/right/top/bottom/centerH/centerV/center/distributeH/distributeV/toFirst/toLast
|
|
|
|
|
|
- `composables/useBatchGenerate.ts` —— 横向/纵向/矩阵/环形 4 种批量生成器,输出 BatchOp[]
|
|
|
|
|
|
- `composables/useClipboard.ts` —— 对象/字段剪贴板
|
|
|
|
|
|
- `transform.copyFields` 工具:MapEditorView `runCopyFields` 读取多选(第 1 个为源,其余目标),prompt 字段名列表,调 `mapEditApi.copyFieldsTo`;撤销时用前置 patch 回滚
|
|
|
|
|
|
- 类型默认 Tab:站点/路径默认 layer/前缀/颜色/线宽,存 localStorage `mapEditor.defaults`
|
|
|
|
|
|
- 图层 Tab:图层名列表 + 可见 / 可选 / 颜色,本地状态
|
|
|
|
|
|
|
|
|
|
|
|
## 阶段 3:AI 生图 + 状态栏 + 项目保存/加载(已完成)
|
|
|
|
|
|
|
|
|
|
|
|
- AiGenerateDialog 通过 `mapEditApi.aiMapGenerate` 真实调用 LLM,后端走 `AiCompletionService.GenerateMapAsync`:用 OpenAI Function Calling 让 LLM 直接调 create_site / create_track / batch_create 等"工具",落地到 SimpleLib
|
|
|
|
|
|
- 入口:EditTopBar 「AI 生图」按钮 → 弹对话框,参数:prompt / mode (sites/tracks/sites+tracks/full) / bounds / referenceImageBase64 / layer / constraints
|
|
|
|
|
|
- 项目保存/加载:EditTopBar「保存」/「另存为」/「加载项目」→ prompt 输入路径 → 调 `mapEditApi.projectSave/Load` → 服务端走 `SimpleProject.ToFile / FromFile`;最近路径缓存到 localStorage `mapEditor.lastProjectPath`
|
|
|
|
|
|
|
|
|
|
|
|
## 阶段 4:MapMonitor 浮动报警卡 + KPI + 实时列表(已完成)
|
|
|
|
|
|
|
|
|
|
|
|
`frontends/apps/simple-platform-vue/src/views/admin/MapMonitorView.vue` 改动:
|
|
|
|
|
|
|
|
|
|
|
|
- 删除原 `AlarmTicker.vue` 底部滚动条
|
|
|
|
|
|
- 新增 `components/map-monitor/FloatingAlarmStack.vue` + `FloatingAlarmCard.vue`,可拖动 / 可吸边 / 可堆叠
|
|
|
|
|
|
- 报警来源走 `useMapEditStream.onAlarm`(订阅 SSE 的 `alarm` 事件,由 AlarmStreamService 1s diff 推送)
|
|
|
|
|
|
- KPI 3 卡:在线车辆 / 运行中任务 / 排队任务
|
|
|
|
|
|
- 实时列表:左侧 Workspace3D + 右侧 VehicleMonitorPanel + SelectionDetailPanel
|
2026-08-26 17:46:52 +08:00
|
|
|
|
- 「定位」按钮通过 `reflectionApi.setSelection('car', id)` 让 Simple3 3D 高亮该车(视觉上等效 flyTo)
|
2026-05-29 18:16:34 +08:00
|
|
|
|
|
|
|
|
|
|
## 阶段 5:OrchestrationView 设计与编排(已完成)
|
|
|
|
|
|
|
|
|
|
|
|
`views/admin/OrchestrationView.vue` 5-Tab 壳:
|
|
|
|
|
|
|
|
|
|
|
|
| Tab | 来源 |
|
|
|
|
|
|
|-----|------|
|
|
|
|
|
|
| 车辆 | 复用现有 `CarPanelView` |
|
|
|
|
|
|
| 进程 | 复用现有 `MissionEditorView` |
|
|
|
|
|
|
| 脚本 | `components/orchestration/ReflectionKindTable.vue`(kind=script):动态列表 + 反射 method 执行 |
|
|
|
|
|
|
| 任务流 | ReflectionKindTable(kind=mission, extraFilter='taskflow')|
|
|
|
|
|
|
| 触发器 | ReflectionKindTable(kind=mission, extraFilter='trigger')|
|
|
|
|
|
|
|
|
|
|
|
|
Tab 状态缓存到 sessionStorage。
|
|
|
|
|
|
|
|
|
|
|
|
## 阶段 6:联调 / 撤销栈做实 / 文档(已完成)
|
|
|
|
|
|
|
|
|
|
|
|
### 撤销栈做实
|
|
|
|
|
|
|
|
|
|
|
|
`composables/useHistory.ts` 提供 `run/undo/redo/composite`,每个命令 `apply/revert` 双向。本次把 MapEditorView 里所有占位 revert 改成真实回滚:
|
|
|
|
|
|
|
|
|
|
|
|
| 命令 | 原 revert | 现 revert |
|
|
|
|
|
|
|------|-----------|-----------|
|
|
|
|
|
|
| `runCreateSite` | delete 创建的 id | (未变)|
|
|
|
|
|
|
| `handleTrackPick` 创建路径 | delete 创建的 id | (未变)|
|
|
|
|
|
|
| `deleteSelection` | ⚠️ 仅本地撤销 | **getBundle 抓快照 → batch.create 重建(id 重排)** |
|
|
|
|
|
|
| `onSetField` 字段修改 | ⚠️ 不回滚 | **getBundle 抓原值 → setField 回去** |
|
|
|
|
|
|
| `applyAlignment` | (已用 patch 反向恢复) | (未变)|
|
|
|
|
|
|
| `applyBatchAsCommand` | (已用 delete 反向移除) | (未变)|
|
|
|
|
|
|
| `runAlongPathSampling`(新增)| —— | delete 所有采样产生的 site id |
|
|
|
|
|
|
| `runCopyFields`(新增)| —— | patch 反向把 targets 字段值恢复 |
|
|
|
|
|
|
|
|
|
|
|
|
### 沿路径采样
|
|
|
|
|
|
|
|
|
|
|
|
- 后端:`POST /projection/map-edit/objects/track/{id}/sample-sites { spacingMm, includeEndpoints?, layer? }` —— 当前在 siteA → siteB 之间欧式直线均分(贝塞尔/弧的真实参数化采样留待后续 Track 子类 PR)
|
|
|
|
|
|
- 前端:选中 1+ 条 track,工具栏「沿路径」→ prompt 间距和端点开关 → 调后端,撤销可回退
|
|
|
|
|
|
|
|
|
|
|
|
### 编译相关清理
|
|
|
|
|
|
|
2026-08-26 17:46:52 +08:00
|
|
|
|
- `Simple3/Recording/`(之前的录制/回放实验目录)误用 `Simple3.Rendering` namespace、`Car` 找不到、`Start(string, out)` 默认参数顺序等 3 个错误 → 修
|
|
|
|
|
|
- `Simple3/Props/UISite.cs` 在 `Simple3.Props` namespace 下 `Workspace.AddProp` 被解析成 `Simple3.Workspace.AddProp` → 改为全限定 `CycleGUI.Workspace.AddProp`
|
|
|
|
|
|
- `Simple3/Workspace/WorkspaceBottomBar.cs` 缺 `using Simple3.Workspace;` → 补
|
2026-05-29 18:16:34 +08:00
|
|
|
|
- `HttpClientHelper.csproj` LangVersion 7.3 → latest
|
|
|
|
|
|
|
|
|
|
|
|
## 已知 TODO(不阻塞 v3 上线)
|
|
|
|
|
|
|
|
|
|
|
|
1. 贝塞尔/弧/Nurbs 路径的真实参数化采样(当前直线均分)
|
|
|
|
|
|
2. 撤销栈跨 Tab / 跨 session 共享(当前仅 MapEditor 视图局部)
|
|
|
|
|
|
3. Workspace3D 真正的 postMessage 'workspace.flyTo' 双向桥(当前用 setSelection 代替)
|
|
|
|
|
|
4. 复制字段 UI 支持类型化字段挑选器(当前 prompt 输入字段名)
|
|
|
|
|
|
5. AI 生图 OAuth/键持久化加密(当前明文存 config)
|
|
|
|
|
|
6. Recording 录制/回放模块未完工(PlaybackController 已修通编译,UI 已挂底栏,但实际录制/回放业务逻辑需要后续单独 PR 完成)
|
|
|
|
|
|
|
|
|
|
|
|
## 启动方式
|
|
|
|
|
|
|
|
|
|
|
|
```
|
2026-08-26 17:46:52 +08:00
|
|
|
|
# 1. 后端 build(Simple3 + MiGu.Server)
|
|
|
|
|
|
dotnet build Simple3\Simple3.csproj
|
2026-05-29 18:16:34 +08:00
|
|
|
|
dotnet build MiGu.Server\MiGu.Server.csproj
|
|
|
|
|
|
|
|
|
|
|
|
# 2. 前端打包并同步到 wwwroot
|
|
|
|
|
|
.\build-platform-frontend.bat
|
|
|
|
|
|
|
2026-08-26 17:46:52 +08:00
|
|
|
|
# 3. 启动平台 + Simple3
|
2026-05-29 18:16:34 +08:00
|
|
|
|
dotnet run --project MiGu.Server # 监听 0.0.0.0:8080
|
2026-08-26 17:46:52 +08:00
|
|
|
|
# Simple3 端口 8222/8223 由 Simple3 自己启动
|
2026-05-29 18:16:34 +08:00
|
|
|
|
|
|
|
|
|
|
# 4. 访问
|
|
|
|
|
|
http://127.0.0.1:8080/admin/map-editor # 地图编辑(v3 四栏壳)
|
|
|
|
|
|
http://127.0.0.1:8080/admin/map-monitor # 地图监控(驾驶舱 + 浮动报警)
|
|
|
|
|
|
http://127.0.0.1:8080/admin/orchestration # 设计与编排(5 Tab)
|
|
|
|
|
|
```
|