配置段/环境变量、Launcher、健康检查 API、OpenAPI 与前后端文案同步;兼容探测旧 SimpleLite 进程名。 Co-authored-by: Cursor <cursoragent@cursor.com>
1947 lines
91 KiB
Markdown
1947 lines
91 KiB
Markdown
# Simple3 三端系统架构设计
|
||
|
||
> **Migu2.0 仓库说明**:平台后端已拆至本仓库,工程名为 **`MiGu.Server`**(原 `Platform.Server`)。Simple3 与前端源码仍在兄弟仓库 `Simple`。下文中的 `MiGu.Server` 即指本仓库 `MiGu.Server/` 目录。
|
||
|
||
> 文档版本:v1.7.0
|
||
> 更新日期:2026-05-20
|
||
> 范围:Simple3(主程序 / 设计端 / 调度引擎宿主 / 进程编排器)+ Platform(业务平台 · 同时承载管理员前端 platform-vue 与运营前端 rcsmonitor-vue · 共用一套 WebAPI · **主入口为 MiGu.Server,登录后拉起 Simple3**)
|
||
|
||
> v1.7.0 变更(多主题色板 · 工业紫默认):
|
||
> - **6 套可切换主题**:`themes.ts` 定义色板(工业紫、深邃蓝、翡翠绿、熔铁赤、石墨钢、琥珀金);默认 **工业紫色** `#6a1b9a`(比 v1.6.2 的 `#641393` 更深更饱和,解决登录后内容区配色过淡)。
|
||
> - **运行时注入**:`applyThemeVars()` 向 `:root` 写入 `--mg-*`;`ui` store 的 `themeId` 持久化到 `localStorage`(键 `simple.ui.state`)。
|
||
> - **ThemeSwitcher**:`AppShell` 顶栏下拉切换;`main.ts` 启动时 `applyCurrentTheme()`。
|
||
> - **壳层变量化**:`AppShell` 侧栏/顶栏/光晕/菜单由硬编码紫改为 `var(--mg-*)`;登录页 `BlankLayout` / `LoginView` 光球与 hero 同步走变量(待办见 §18)。
|
||
> - 详见 §17.7、§18「实现进度与待办」。
|
||
|
||
> v1.6.2 变更(全站统一玻璃风):
|
||
> - **品牌主色回归 v1.6 的 `#641393`**:与登录页 hero 一致;保留 FRLD logo 仍在侧栏左上角;侧栏 / 顶导 / 内容卡片采用统一玻璃设计令牌(`--mg-glass-*`、`--mg-radius` 14/20px)。
|
||
> - **整站背景深紫渐变**:`body` 固定 `radial-gradient + linear-gradient(135deg,#1a0930 → #2d1456 → #0f0420)`;AppShell 内悬浮三颗低亮度光球(drift 动画 22s)增加层次感。
|
||
> - **登录页玻璃 hero 还原**:双栏 hero · 「迷」徽标 · 18 颗 twinkle 星 · 三色 drift 光球 · `mg-glass-lg` 主卡(白色 8% 半透明 + 28px blur + 双层 inset 边框)。
|
||
> - **AppShell 玻璃化**:侧栏 `rgba(22,4,31,0.85→0.88)` 深紫渐变 + 18px backdrop blur + 菜单 active 状态紫色渐变背景 + 3px inset 紫光;顶导 `rgba(22,4,31,0.6)` 玻璃;底栏 `rgba(22,4,31,0.25)` 玻璃;用户头像 / 标签 / dropdown 全部玻璃化。
|
||
> - **内容区卡片自动玻璃化**:`<el-main class="main mg-content">` 容器内所有 `el-card / el-statistic / el-table / el-descriptions / el-input / el-tag / el-progress / el-collapse / el-radio-button / el-input-number / el-switch / el-pagination` 均沿用紫黑半透明 + 14px 圆角 + hover 上浮(translateY -2px)+ shadow 升级;KPI 行 `class="kpi-row"` 内 `el-statistic` 自动玻璃卡。
|
||
> - **路由切换微动效**:`<router-view>` 包裹 fade-up(250ms cubic-bezier .25,.8,.25,1),轻盈不花哨。
|
||
> - 详见 §17「视觉规范」。
|
||
|
||
> v1.6.1 变更(视觉对齐 FRLD · 已在 v1.6.2 中部分回退):
|
||
> - **侧边栏左上角加 FRLD(法睿兰达 FAIRYLAND)logo**:`public/FRLD-logo-white.png` 展开态 36px 高、`public/FRLD-logo-white-no_title.png` 折叠态 26px 高 + 缩写「迷毂」。Logo 来源 `E:\ddms\frontend\public`。**v1.6.2 保留 FRLD logo,但取消 #7c3aed 主色与 ddms 风格菜单态,全部回到 v1.6 玻璃风。**
|
||
|
||
> v1.6 变更(品牌 & 视觉规范):
|
||
> - **产品品牌命名定为「迷毂」**:Vue 外壳产品代号、登录窗 / 侧边栏 logo、`<title>`、用户可见文案、`favicon` 全部统一为「迷毂」;后端工程标识 `MiGu.Server` / 前端工程目录 `simple-platform-vue` 不变(避免影响 csproj/pnpm 包名)。
|
||
> - **品牌主色紫色系(v1.6 初版 #641393,v1.6.1 调整为 #7c3aed)**:全站统一紫色调;Element Plus 通过 CSS 变量覆盖(`--el-color-primary` 与 `--el-color-primary-rgb` 双重保险);状态色保持系统默认。
|
||
> - **登录窗背景**:使用品牌图片资源 `frontends/apps/simple-platform-vue/public/login-bg.jpg`(原始素材 `wall_Beach.jpg`,1.8 MB)+ 紫色径向 + 线性渐变叠加。
|
||
> - 详见 §17「视觉规范」。
|
||
|
||
> v1.5 变更:
|
||
> - **持久层多 Provider 支持**:抽象层基于 EF Core,新增对 **MySQL / PostgreSQL / SQL Server** 的原生支持;SQLite 仍为默认/边缘单机首选。
|
||
> - **高可用方案按 DB 矩阵化**:除 ROSE HA(SQLite 块级镜像)外,新增 **MySQL InnoDB Cluster / MGR**、**PostgreSQL Patroni / 流复制**、**SQL Server Always On AG** 三种企业级 HA 路径;现场可根据已有 IT 基础设施挑选。
|
||
> - 新增 §7.4–§7.7 四类 DB 部署形态详述、选型矩阵、连接串与配置示例、迁移注意事项。
|
||
|
||
> v1.4 变更(保留):
|
||
> - **明确进程编排归属**:Platform 后端进程 `MiGu.Server.exe` 不再被视为"独立的业务平台服务",而是 Simple3 内置 `SystemMission`(`StartPlatformMission`)拉起、被 Simple3 Bootstrapper 守护的**受控子进程**;RCSMonitor 不存在独立后端进程,复用 MiGu.Server。
|
||
> - **整体定位章节重写**:明确"两类后端可执行文件 + 一个进程编排者"的关系,避免读者误以为 Platform 是用 Windows Service / systemd 独立部署的服务。
|
||
|
||
> v1.3 变更(保留):
|
||
> 1. **取消 RCSMonitor.Server**:`rcsmonitor-vue` 不再有独立后端进程,直接连 MiGu.Server;由 JWT 中的 `scope=RCSMonitor` + 角色权限码 + `WidgetGrant` 三层限制可见控件与可调用 API。
|
||
> 2. **3D 渲染基座定为 webVRender**:复用 Simple3 WebTerminal 已经提供的 webVRender,以 Web Component / iframe 嵌入到 platform-vue 与 rcsmonitor-vue,两端共享同一份 Workspace 协议(PutModel / PutPointCloud / SetCamera 等 DTO)。
|
||
> 3. **反向代理选定 YARP**:MiGu.Server 内置 [YARP](https://microsoft.github.io/reverse-proxy/) 做 `/api/sl/*` → Simple3 WebAPI 的反代;带鉴权与审计中间件。
|
||
> 4. **运行模式持久化到 `simple.json`**:登录窗"记住模式"勾选后写入 `simple.json.runMode`;下次启动直接进入。
|
||
> 5. **Web-Enabled 下严禁同时本地操作**:CycleGUI 主窗只剩"服务状态窗",所有业务面板硬性隐藏;不提供"临时启用本地 UI"开关。
|
||
> 6. **共享前端组件库**:使用 pnpm workspace + `frontends/packages/sl-controls`,封装 Workspace3D / 地图 / 任务 / CAD 等可复用 Vue 组件。
|
||
|
||
---
|
||
|
||
## 目录
|
||
|
||
1. [总体目标与拆分原则](#1-总体目标与拆分原则)
|
||
2. [顶层系统架构(C4 - 容器视图)](#2-顶层系统架构c4---容器视图)
|
||
3. [启动登录与运行模式](#3-启动登录与运行模式)
|
||
4. [进程拓扑与生命周期](#4-进程拓扑与生命周期)
|
||
5. [三端职责矩阵](#5-三端职责矩阵)
|
||
6. [共享内核分层](#6-共享内核分层)
|
||
7. [数据库与高可用(多 Provider)](#7-数据库与高可用多-provider)
|
||
8. [用户 / 权限模型(含控件级权限)](#8-用户--权限模型含控件级权限)
|
||
9. [平台配置中心](#9-平台配置中心)
|
||
10. [关键交互序列](#10-关键交互序列)
|
||
11. [通信协议矩阵](#11-通信协议矩阵)
|
||
12. [部署拓扑](#12-部署拓扑)
|
||
13. [仓库与解决方案规划](#13-仓库与解决方案规划)
|
||
14. [落地路线图](#14-落地路线图)
|
||
15. [已确认决策](#15-已确认决策)
|
||
16. [现有代码影响面](#16-现有代码影响面)
|
||
17. [视觉规范(v1.6 新增)](#17-视觉规范v16-新增)
|
||
18. [实现进度与待办(对照代码库)](#18-实现进度与待办对照代码库)
|
||
|
||
---
|
||
|
||
## 1. 总体目标与拆分原则
|
||
|
||
### 1.1 整体定位
|
||
|
||
一套为 AGV/AMR 现场打造的「**设计 → 调度 → 运营监控**」三端协同系统。
|
||
|
||
**三个"端"对应三套用户体验,但只有两类后端可执行文件,且都由 Simple3 统一编排:**
|
||
|
||
| 端 | 前端载体 | 后端可执行文件 | **启动者** | 角色 | 写权限 |
|
||
|----|----------|----------------|------------|------|--------|
|
||
| **Simple3 桌面端** | CycleGUI 客户端 | `Simple3.exe` 自身 | 用户双击 / 服务管理器 | 主程序 + 调度引擎宿主 + 全功能 WebAPI 提供者 + **进程编排器(Bootstrapper + SystemMission)** | **全功能** |
|
||
| **Platform 管理端** | `platform-vue` (Vue 3 SPA) | `MiGu.Server.exe` | **Simple3 内置 `SystemMission.StartPlatformMission` 拉起**(Web-Enabled 时自动 spawn;崩溃由 Simple3 Watchdog 重启) | **Simple3 全能力套壳**:管理员侧 Vue 前端复刻所有设计/调度控件 + 业务平台特有能力(配置中心 / 外部对接 / 库位 / 账号) | **全功能**(等价 Simple3) |
|
||
| **RCSMonitor 运营端** | `rcsmonitor-vue` (Vue 3 SPA) | **共用 `MiGu.Server.exe`**(无独立后端进程) | 随 MiGu.Server 一起被 Simple3 拉起 | 运营监控前端:按 `scope=RCSMonitor` + 角色权限 + WidgetGrant 三层裁剪 UI;可对任务/车辆执行白名单运维动作 | **受限**(仅运维白名单) |
|
||
|
||
**关键澄清(v1.4 重点):**
|
||
|
||
- **后端可执行文件只有 2 个**:`Simple3.exe`、`MiGu.Server.exe`。
|
||
- **进程启动只有 1 个真正的入口**:用户/服务管理器只启动 `Simple3.exe`,MiGu.Server 由 Simple3 自己拉起,**不需要也不允许独立安装为 Windows Service**。
|
||
- **进程编排归属 Simple3**:`SystemMission` 是 Simple3 自带的 Mission 体系扩展(与业务 Mission 区分开),专门负责拉起/守护/优雅停止 MiGu.Server。Bootstrapper 监听心跳、按指数退避重启、统一记录 OpsAuditLog。
|
||
- **Vue 两份产物,同一进程托管**:MiGu.Server 在 `/admin/*` 路径下托管 `platform-vue`,在 `/monitor/*` 路径下托管 `rcsmonitor-vue`。
|
||
- **鉴权与限权完全在 MiGu.Server 完成**:RCSMonitor 不持有任何独立后端代码(没有 `RCSMonitor.Server.exe`、没有独立库)。
|
||
- **Desktop-Only 模式下,SystemMission 不触发**:MiGu.Server 根本不会启动,Vue 端无法访问。
|
||
|
||
> 一句话:**用户点 Simple3.exe,由 Simple3 通过 Mission 把 Platform 后端拉起来;Platform 后端再把两套 Vue 端服好。**
|
||
|
||
### 1.2 核心拆分原则
|
||
|
||
1. **Crash-Isolation(搞不崩主服务)**
|
||
Platform / RCSMonitor 对**地图/任务/车辆等写操作**都通过 Simple3 的 `/api/*` 网关;主服务侧做白名单 + 幂等校验 + 频次限流 + 审计。Platform-Vue 走完整 API 集,RCSMonitor-Vue 仅限运维白名单 `/api/ops/*`。
|
||
|
||
2. **共享数据模型,独立运行时**
|
||
地图、车辆、任务三端共用 `SimpleCore` 的 DTO;调度引擎只在 Simple3 里跑,Platform 只持有"投影"。
|
||
|
||
3. **库分离 + Provider 抽象**(详见 §7)
|
||
- `simple_main` 由 Simple3 持有;`platform` 由 Platform 持有(含 RCSMonitor 审计/标注);不再有独立的 `rcsmonitor_local`。
|
||
- 持久层基于 **EF Core**,**通过 Provider 切换底层数据库**:默认 **SQLite**(边缘单机,配 ROSE HA);可选 **MySQL / PostgreSQL / SQL Server**,匹配现场已有 IT 基础设施与企业级 HA 能力(详见 §7.4–§7.7)。
|
||
- 高可用方案随 Provider 不同:SQLite 用 ROSE HA;MySQL 用 InnoDB Cluster;PostgreSQL 用 Patroni;SQL Server 用 Always On AG。
|
||
|
||
4. **统一协议层**
|
||
所有进程间调用统一 **WebAPI(REST/JSON)+ WebSocket 事件流**;Vue 端直接对接 Platform 后端的 REST + WS;Platform 后端用 **YARP** 反代 Simple3 的设计/调度 API。
|
||
|
||
5. **统一身份**
|
||
`SimpleShared.Auth` 提供 JWT + RBAC;Platform 是主权限源(在线时),Simple3 在 Desktop-Only 下用本地用户表降级。
|
||
|
||
6. **运行模式互斥(强约束)**
|
||
- **Desktop-Only**:CycleGUI 客户端独占;WebAPI / Platform **不启动**。
|
||
- **Web-Enabled**:WebAPI 启动;Platform 子进程启动;CycleGUI 客户端**所有业务面板硬性隐藏**,仅保留"服务状态窗";**不允许"临时启用本地 UI"开关**——任何本地操作必须重启进设计模式。
|
||
- 模式由**启动登录界面**选择并持久化到 **`simple.json.runMode`**;下次启动可勾选"记住选择"直接进入。
|
||
|
||
7. **控件级权限**
|
||
Platform / RCSMonitor 登录后向 `SimpleShared.Auth` 拉取 `EffectivePermissions { allowedOps[], visibleWidgets[] }`;Vue 渲染器按集合裁剪面板、按钮、菜单、右键项。
|
||
|
||
---
|
||
|
||
## 2. 顶层系统架构(C4 - 容器视图)
|
||
|
||
```mermaid
|
||
flowchart TB
|
||
subgraph Users["使用方"]
|
||
U1["现场工程师 (CycleGUI 桌面)"]
|
||
U2["管理员 (浏览器)"]
|
||
U3["运营 / 班组长 (浏览器)"]
|
||
U4["第三方 MES / WMS / RCS"]
|
||
end
|
||
|
||
subgraph Host["主控宿主机 / 边缘服务器"]
|
||
subgraph SL["Simple3 主进程 (CycleGUI + ASP.NET Core 8)"]
|
||
direction TB
|
||
SL_Login["启动登录窗<br/>(模式选择 Desktop / Web)"]
|
||
SL_UI["CycleGUI 客户端<br/>(Desktop-Only: 全功能<br/>Web-Enabled: 仅状态窗)"]
|
||
SL_Boot["Bootstrapper<br/>(进程守护 + 心跳)"]
|
||
SL_Sched["SimpleScheduler 调度引擎"]
|
||
SL_Domain["领域服务<br/>(SimpleCore + 命令总线)"]
|
||
SL_API["全功能 WebAPI + WS Hub<br/>(Kestrel)<br/>(仅 Web-Enabled 启动)"]
|
||
SL_WV["webVRender Web Terminal<br/>(已有 :8223)<br/>(Vue 端嵌入)"]
|
||
SL_DB[("SQLite: simple_main.db<br/>WAL")]
|
||
end
|
||
|
||
subgraph PL["Platform 后端 (ASP.NET Core 8 WebAPI)"]
|
||
direction TB
|
||
PL_Static["静态资源<br/>/admin/* → platform-vue dist<br/>/monitor/* → rcsmonitor-vue dist"]
|
||
PL_API["Platform WebAPI<br/>(配置中心 / 外部对接 / 库位 / 账号)"]
|
||
PL_YARP["YARP 反代<br/>/api/sl/* → Simple3 WebAPI<br/>+ Auth/审计中间件"]
|
||
PL_Auth["SimpleAuth<br/>(JWT 签发 + Scope 校验)"]
|
||
PL_Adp["外部系统适配器<br/>(MES / WMS / RCS)"]
|
||
PL_DB[("SQLite: platform.db<br/>WAL")]
|
||
end
|
||
end
|
||
|
||
subgraph Vues["两份 Vue 编译产物 (同一进程托管)"]
|
||
AdminVue["platform-vue<br/>(管理员全功能)"]
|
||
MonVue["rcsmonitor-vue<br/>(运营按权限)"]
|
||
end
|
||
|
||
subgraph External["外部"]
|
||
Veh["AGV 车端"]
|
||
TPS["第三方设备<br/>(电梯 / 充电桩 / IO)"]
|
||
end
|
||
|
||
U1 --> SL_Login
|
||
SL_Login --> SL_UI
|
||
U2 -- "https://host:8080/admin" --> PL_Static
|
||
U3 -- "https://host:8080/monitor" --> PL_Static
|
||
U4 -- "REST / OPC-UA" --> PL_API
|
||
PL_Static --> AdminVue
|
||
PL_Static --> MonVue
|
||
|
||
AdminVue -- "REST + WSS" --> PL_API
|
||
MonVue -- "REST + WSS (scope=RCSMonitor)" --> PL_API
|
||
AdminVue -. "iframe / WebComponent" .-> SL_WV
|
||
MonVue -. "iframe / WebComponent (read-only)" .-> SL_WV
|
||
|
||
PL_API --> PL_Auth
|
||
PL_API --> PL_YARP
|
||
PL_YARP -- "WebAPI + WS<br/>(Web-Enabled 时)" --> SL_API
|
||
PL_API --> PL_DB
|
||
PL_API --> PL_Adp
|
||
|
||
SL_Boot == "SystemMission.StartPlatformMission<br/>spawn + heartbeat + watchdog" ==> PL
|
||
|
||
SL_API <--> SL_Sched
|
||
SL_API <--> SL_Domain
|
||
SL_Domain --> SL_DB
|
||
|
||
SL_Sched -- "TCP / WS / OPC-UA" --> Veh
|
||
PL_API --> TPS
|
||
```
|
||
|
||
**要点:**
|
||
|
||
- **只有两个后端可执行文件**:`Simple3.exe` 与 `MiGu.Server.exe`;RCSMonitor 不再有独立后端。
|
||
- **`MiGu.Server.exe` 由 Simple3 的 SystemMission 拉起**:用户只启动 Simple3;Web-Enabled 时 `StartPlatformMission` 自动 spawn MiGu.Server,子进程心跳异常由 Bootstrapper 重启。
|
||
- **`PL_Static` 同一进程双 SPA 托管**:浏览器访问路径决定加载哪份 dist,登录时也按路径决定 `scope` 参数。
|
||
- **`PL_YARP` 把 `/api/sl/*` 反代到 Simple3**:YARP 在请求转发前后挂中间件做 JWT 校验、权限码二次确认、写操作审计、`Idempotency-Key` 透传、Scope 检查(RCSMonitor 的请求仅允许命中 `/api/ops/*` 这一前缀)。
|
||
- **3D 由 Simple3 的 webVRender 提供**:Vue 端通过 iframe 或 Web Component 嵌入 webVRender 的页面,业务交互(选择、点击坐标等)通过 `postMessage` 与 Vue 桥接。
|
||
- **Desktop-Only 模式**:`SL_API`、`PL` 都不启动;Vue 无法访问;CycleGUI 是唯一入口。
|
||
- **Web-Enabled 模式**:CycleGUI 退化为状态窗;所有业务操作通过 Vue 完成;硬性不允许同时本地操作。
|
||
|
||
---
|
||
|
||
## 3. 启动登录与运行模式
|
||
|
||
### 3.1 启动流程
|
||
|
||
```mermaid
|
||
flowchart TB
|
||
Start([Simple3.exe 启动]) --> CheckPrev{simple.json 中<br/>runMode 已记忆?}
|
||
CheckPrev -- 否 --> Login[弹出登录窗<br/>Simple3 Boot Login]
|
||
CheckPrev -- 是 --> AutoLogin[自动按记忆模式登录<br/>仍需鉴权身份]
|
||
Login --> Form
|
||
AutoLogin --> ModeSwitch
|
||
|
||
subgraph Form[登录窗内容]
|
||
F1[用户名 / 密码]
|
||
F2[运行模式 RadioButtons]
|
||
F2a[Desktop-Only]
|
||
F2b[Web-Enabled]
|
||
F3[记住选择 CheckBox<br/>勾选后写 simple.json.runMode]
|
||
F4[登录按钮]
|
||
end
|
||
|
||
Form --> Auth[本地用户表认证<br/>SimpleShared.Auth]
|
||
Auth -- 失败 --> Login
|
||
Auth -- 成功 --> Persist{勾选了<br/>记住选择?}
|
||
Persist -- 是 --> WriteCfg[写 simple.json<br/>runMode + rememberRunMode=true]
|
||
Persist -- 否 --> ModeSwitch
|
||
WriteCfg --> ModeSwitch
|
||
|
||
ModeSwitch{运行模式?}
|
||
ModeSwitch -- Desktop-Only --> Path1
|
||
ModeSwitch -- Web-Enabled --> Path2
|
||
|
||
subgraph Path1[Desktop-Only 路径]
|
||
D1[启动 CycleGUI 全功能 UI]
|
||
D2[启动调度引擎]
|
||
D3[加载场景 / 插件]
|
||
D4["不启动 WebAPI / Platform"]
|
||
end
|
||
|
||
subgraph Path2[Web-Enabled 路径]
|
||
W1[启动 Kestrel + WebAPI]
|
||
W2[启动调度引擎]
|
||
W3[加载场景 / 插件]
|
||
W4[启动 WebTerminal]
|
||
W5[启动 MiGu.Server.exe]
|
||
W6[CycleGUI 仅渲染服务状态窗<br/>所有业务面板硬性隐藏]
|
||
W7[等待 Vue 端登录]
|
||
end
|
||
```
|
||
|
||
### 3.2 登录界面(CycleGUI Panel)
|
||
|
||
字段与控件:
|
||
|
||
| 元素 | 控件 | 说明 |
|
||
|------|------|------|
|
||
| 标题 | Label | "Simple3 · 启动登录" |
|
||
| 用户名 | TextInput | 默认上次登录用户 |
|
||
| 密码 | TextInput (password) | — |
|
||
| 运行模式 | RadioButtons | `Desktop-Only` / `Web-Enabled` |
|
||
| 记住选择 | CheckBox | 勾选后写入 `simple.json.runMode` 与 `simple.json.rememberRunMode=true` |
|
||
| 监听地址(Web-Enabled 显示) | TextInput | 默认 `0.0.0.0` |
|
||
| WebAPI 端口(Web-Enabled) | NumberInput | 默认 `7001` |
|
||
| Platform 端口(Web-Enabled) | NumberInput | 默认 `8080`(同时承载 admin/monitor 两份 SPA) |
|
||
| 高级(Web-Enabled 折叠) | Collapsing | webVRender 端口 / Swagger 是否启用 / CORS 白名单 |
|
||
| 登录按钮 | Button | 通过后销毁登录窗,进入选定模式 |
|
||
| 退出按钮 | Button | 不进入主程序,退出进程 |
|
||
|
||
> 实现位置:新增 `Simple3/UI/BootLoginPanel.cs`,由 `Program.Main` 在 `Enssentials.Load` 之后、`Startup.EntryPoint` 之前调用 `GUI.PromptAndWaitPanel(BootLoginPanel.Build())`(阻塞式模态)。
|
||
|
||
#### simple.json 增量字段
|
||
|
||
```json
|
||
{
|
||
"runMode": "WebEnabled", // "DesktopOnly" | "WebEnabled"
|
||
"rememberRunMode": true,
|
||
"webApi": {
|
||
"host": "0.0.0.0",
|
||
"port": 7001,
|
||
"wsPort": 7002,
|
||
"enableSwagger": false
|
||
},
|
||
"platform": {
|
||
"port": 8080,
|
||
"wsPort": 8081
|
||
},
|
||
"webVRender": {
|
||
"port": 8223
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3.3 模式切换与互斥保证(强约束)
|
||
|
||
| 场景 | 行为 |
|
||
|------|------|
|
||
| Desktop-Only 运行中 | Kestrel 不监听任何端口;MiGu.Server 不 spawn;尝试连接 7001/8080 直接 ECONNREFUSED |
|
||
| Desktop-Only → Web-Enabled | **必须退出 Simple3 重新登录**;不支持热切(避免半启动状态) |
|
||
| Web-Enabled 运行中 | CycleGUI 主窗只显示状态窗(运行时长 / 在线用户 / 端口 / 主备状态)+「停止」按钮 |
|
||
| Web-Enabled 下用户尝试本地控件 | **所有业务面板硬性不渲染**;Workspace 视口也不显示;用户无法通过任何方式重新启用 |
|
||
| Web-Enabled 异常退出 | Watchdog 重新拉起,恢复到 Web-Enabled;不强迫用户重选 |
|
||
| 想取消"记住模式" | 启动时按住 `Shift` 或运行 `Simple3.exe --re-login` 强制弹出登录窗 |
|
||
| 远程开关模式 | Platform 管理员可以发 `POST /api/sl/runmode/reset` 把 `rememberRunMode` 置为 `false`,**仅在下次重启时生效** |
|
||
|
||
### 3.4 服务状态窗(Web-Enabled 唯一可见的 CycleGUI 面板)
|
||
|
||
```text
|
||
┌──────────────────────────────────────────┐
|
||
│ Simple3 Service Status │
|
||
├──────────────────────────────────────────┤
|
||
│ 模式: Web-Enabled │
|
||
│ 启动时间: 2026-05-18 09:00:00 │
|
||
│ 运行时长: 00:23:15 │
|
||
│ WebAPI: http://0.0.0.0:7001 [OK] │
|
||
│ WebSocket: ws://0.0.0.0:7002 [OK] │
|
||
│ webVRender: http://0.0.0.0:8223 [OK] │
|
||
│ Platform: :8080 [Running, pid=12345] │
|
||
│ 节点角色: Active (ROSE) │
|
||
│ 在线 Vue 客户端: 7 (admin=3, monitor=4) │
|
||
│ 调度循环: 50Hz | 任务: 14 / 32 │
|
||
│ │
|
||
│ [Open Logs] [Restart Web] [Shutdown] │
|
||
└──────────────────────────────────────────┘
|
||
```
|
||
|
||
> 状态窗**不包含**"启用本地 UI"按钮——切回设计模式必须重启进程并选择 Desktop-Only。
|
||
|
||
---
|
||
|
||
## 4. 进程拓扑与生命周期
|
||
|
||
### 4.1 进程关系图
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
A["Simple3.exe<br/>启动 + 登录"] --> Mode{运行模式}
|
||
|
||
Mode -- Desktop-Only --> D[CycleGUI 全功能 UI]
|
||
D --> SchedD[调度引擎]
|
||
D --> DB1D[(simple_main.db)]
|
||
|
||
Mode -- Web-Enabled --> WHost[Kestrel + WebAPI :7001/7002]
|
||
WHost --> SchedW[调度引擎]
|
||
WHost --> DB1W[(simple_main.db)]
|
||
WHost --> WV[WebTerminal :8223<br/>webVRender]
|
||
WHost --> StatusPanel[CycleGUI 状态窗]
|
||
|
||
subgraph SysMis["Simple3 SystemMission 体系"]
|
||
E["StartPlatformMission<br/>(SystemMission 子类)"]
|
||
SM_Reg["SystemMissionRegistry"]
|
||
SM_Hb["HeartbeatChannel<br/>(named pipe)"]
|
||
end
|
||
WHost --> SysMis
|
||
E ==> P["MiGu.Server.exe<br/>(ASP.NET Core WebAPI + YARP)<br/>:8080/8081"]
|
||
P --> PStatic["静态托管 2 份 dist:<br/>/admin → platform-vue<br/>/monitor → rcsmonitor-vue"]
|
||
P --> PDB[(platform.db)]
|
||
P <-. JSON heartbeat .-> SM_Hb
|
||
|
||
subgraph 守护
|
||
W["ProcessWatchdog<br/>(指数退避重启 + 优雅停止)"]
|
||
end
|
||
SysMis --- W
|
||
W -. monitor .- P
|
||
```
|
||
|
||
### 4.2 SystemMission 体系(v1.4 新增章节)
|
||
|
||
Simple3 现有 `Mission` 是业务任务(运送/搬运),新增 **`SystemMission`** 作为同一基类的"系统级 Mission",用于拉起并守护进程级服务。它**不参与调度引擎的 DispatchLoop**,由 Bootstrapper 直接驱动。
|
||
|
||
**关键类:**
|
||
|
||
| 类型 | 类型 / 命名空间 | 职责 |
|
||
|------|------------------|------|
|
||
| `SystemMission`(抽象) | `Simple3.RCS.SystemMissions` | 继承自现有 `Mission`,新增 `Spawn() / Stop() / Heartbeat()` 等抽象方法 |
|
||
| `StartPlatformMission` | `Simple3.RCS.SystemMissions` | 拉起 `MiGu.Server.exe`;通过命名管道 `\\.\pipe\simple-bootstrap` 接收心跳 |
|
||
| `SystemMissionRegistry` | `Simple3.Bootstrap` | 单例,注册所有 SystemMission;Web-Enabled 启动时遍历 `Spawn()`;进程退出时遍历 `Stop()` |
|
||
| `ProcessHost` | `Simple3.Bootstrap` | 封装 `System.Diagnostics.Process` + 重定向标准输出到日志 + 退出码捕获 |
|
||
| `HeartbeatChannel` | `Simple3.Bootstrap` | 命名管道服务端;JSON 协议 `{ "ts", "rss", "queueDepth", "status" }`;3 个周期未达 → 标记不健康 |
|
||
| `ProcessWatchdog` | `Simple3.Bootstrap` | 不健康时 `Stop() + Spawn()`;指数退避 1s → 2s → 4s → 8s → 30s(上限) |
|
||
| `RunMode`(枚举) | `Simple3.Bootstrap` | `DesktopOnly` / `WebEnabled` |
|
||
|
||
**生命周期:**
|
||
|
||
```text
|
||
Simple3 启动 (Web-Enabled)
|
||
├─ Kestrel Up :7001/7002
|
||
├─ WebTerminal Up :8223
|
||
├─ SchedulerRuntime.Start()
|
||
└─ SystemMissionRegistry.SpawnAll()
|
||
└─ StartPlatformMission.Spawn()
|
||
├─ ProcessHost.Start("MiGu.Server.exe", args)
|
||
├─ HeartbeatChannel.Listen(pipeName)
|
||
└─ Watchdog.Track(pid)
|
||
|
||
每 5s:
|
||
HeartbeatChannel ← MiGu.Server (JSON tick)
|
||
|
||
异常:
|
||
Watchdog 触发 → ProcessHost.Kill() → 退避等待 → Spawn() 重试
|
||
连续 5 次失败 → 状态窗高亮 "Platform Down",停止重试,需人工介入
|
||
|
||
Simple3 优雅停机:
|
||
SystemMissionRegistry.StopAll()
|
||
└─ StartPlatformMission.Stop()
|
||
├─ 发送 SIGTERM 等价(命名管道 "shutdown" 消息)
|
||
├─ 等待 MiGu.Server 完成 IHostedService.StopAsync (≤ 30s)
|
||
└─ 超时则 ProcessHost.Kill()
|
||
```
|
||
|
||
**实现要点:**
|
||
|
||
- **位置**:新建 `Simple3/Bootstrap/` 与 `Simple3/RCS/SystemMissions/`。
|
||
- **不写入主库 Missions 表**:SystemMission 是进程级配置,不参与项目序列化;存储在 `simple_main.db.SystemMissionConfig`(或直接读 `simple.json`)。
|
||
- **崩溃隔离**:Platform 异常不影响 Simple3 调度循环;MiGu.Server 也实现 `IHostedService.StopAsync` 做 WAL Checkpoint + WS 排空 → 给 ROSE 释放磁盘。
|
||
- **多实例预防**:通过命名互斥体 + `simple.json.allowMultiple=false`(已有)确保 Simple3 唯一;MiGu.Server 启动时校验"父进程是否为 Simple3",否则拒绝启动(防止有人手动双击 `MiGu.Server.exe`)。
|
||
- **静态资源**:MiGu.Server 用 `MapWhen + UseStaticFiles + UseSpa` 各挂一份 `index.html`。
|
||
|
||
---
|
||
|
||
## 5. 三端职责矩阵
|
||
|
||
| 维度 | Simple3 桌面端 | **Platform 管理端(platform-vue)** | **RCSMonitor 运营端(rcsmonitor-vue)** |
|
||
|------|---------------------|------------------------------------------|------------------------------------------|
|
||
| 地图(站点/轨道/区域)编辑 | **读写**(Desktop-Only) | **全功能读写**(Vue 地图控件内嵌Simple3地图) | 只读投影,不可编辑 |
|
||
| 任务编排(Mission/Recipe) | **读写** | **全功能读写**(含 Demand / Recipe) | 基础动作:暂停/取消/重派/优先级 |
|
||
| 车辆配置(参数 / 维护策略) | **读写** | **全功能读写** | 基础动作:暂停/继续/结束任务/上线/离线/手动充电等 |
|
||
| CAD 工具 | **可用** | **可用**(Vue 调用 `/api/sl/cad/*`) | 不可用 |
|
||
| 自定义字段 / 图层 | **可用** | **可用** | 只读 |
|
||
| 调度引擎(DispatchLoop) | 进程内拥有 | 远程订阅状态 + 全 API 操作 | 远程订阅状态 + 受限 API |
|
||
| 车端通信 | 拥有 | 不直连,只看投影 | 不直连,只看投影 |
|
||
| 3D 视口 | 本地 OpenGL(CycleGUI 原生) | **嵌入 Simple3 webVRender**(全功能交互) | **嵌入 Simple3 webVRender**(只读 + 圈选) |
|
||
| 系统级配置 | 局部(Desktop-Only) | **全局编辑 + 下发** | 不可编辑 |
|
||
| 外部对接(MES/WMS/RCS) | 不涉及 | **唯一入口** | 不涉及 |
|
||
| 路径规划/交通/充电策略 | 算法 + 调试 | **可视化编辑 + 下发** | 只读 |
|
||
| 权限/角色管理 | 本地用户表(启动登录用) | **统一管理(主源)** | 仅查看自身权限 |
|
||
| 库位 / 出入库 | 地图层(库位几何) | **业务主体 + 库存** | 监控视图(按权限) |
|
||
| 调度回放 / 日志 | 短期内存 | **长期归档 + 检索** | 故障快照 + 备注 |
|
||
| 自定义控件管理 | 本地配置 | **设计 + 发布** | 接收推送 + 按权限渲染 |
|
||
|
||
> 两个前端共用同一个 MiGu.Server 后端,区别在登录时申请的 `scope`(`Platform` vs `RCSMonitor`)与对应角色绑定的权限码 / WidgetGrant。
|
||
|
||
### 5.1 RCSMonitor 基础动作白名单(初版)
|
||
|
||
| 操作 | 权限码 | 影响范围 | 二次确认 |
|
||
|------|--------|----------|---------|
|
||
| 暂停车辆 | `ops.car.pause` | 单车 | 否 |
|
||
| 恢复车辆 | `ops.car.resume` | 单车 | 否 |
|
||
| 回原点 | `ops.car.gohome` | 单车 | 是 |
|
||
| 重置车辆会话 | `ops.car.resetSession` | 单车 | 是 |
|
||
| 手动充电 | `ops.car.manualCharge` | 单车 | 否 |
|
||
| 暂停任务 | `ops.task.pause` | 单任务 | 否 |
|
||
| 取消任务 | `ops.task.cancel` | 单任务 | 是 |
|
||
| 重派任务 | `ops.task.reassign` | 单任务 | 是 |
|
||
| 提升优先级 | `ops.task.boostPriority` | 单任务 | 否 |
|
||
| 写运营备注 | `monitor.note.write` | 标注层(写 platform.db) | 否 |
|
||
|
||
> **限权双保险**:① 浏览器侧按 `allowedOps` 隐藏按钮;② MiGu.Server YARP 中间件在转发前再次校验。`scope=RCSMonitor` 的请求路径必须落在 `/api/sl/ops/*` 白名单前缀内,否则 403。
|
||
|
||
### 5.2 Platform 管理端设计权限示例(全功能套壳)
|
||
|
||
| 操作 | 权限码 | 控件位置(platform-vue) |
|
||
|------|--------|---------------------------|
|
||
| 创建/编辑站点 | `map.site.write` | 地图设计页 · 工具栏 |
|
||
| 创建/编辑轨道(含曲线) | `map.track.write` | 地图设计页 · 工具栏 |
|
||
| 编辑车辆参数 | `vehicle.config.write` | 车辆配置页 |
|
||
| 创建/编辑 Mission | `mission.write` | 任务编排页 |
|
||
| 加载/保存项目 | `project.write` | 顶栏 |
|
||
| 触发 CAD 工具 | `cad.tool.run` | CAD 工具栏 |
|
||
| 配置中心编辑 | `config.<section>.write` | 配置中心各分页 |
|
||
| 用户/角色管理 | `auth.user.write` / `auth.role.write` | 系统管理页 |
|
||
| 切换运行模式(远程) | `system.runmode.reset` | 系统管理页 → 危险操作 |
|
||
|
||
### 5.3 Platform 平台能力补充(设备统一接入与管理)
|
||
|
||
Platform 内置通用设备管理模块(`DeviceHub`),作为所有外围设备的统一接入层与运维入口,覆盖注册、配置、状态监控、告警与审计。
|
||
|
||
**内置接入设备类型:**
|
||
|
||
- 电梯、卷帘门、安全门
|
||
- 充电桩(自动对接协议)
|
||
- 无线 AP、网络交换机
|
||
- 视频摄像头、读码器、PLC
|
||
|
||
**架构原则(一次适配,后续复用):**
|
||
|
||
- **驱动式插件架构**:设备能力抽象为 `IDeviceDriver` + `IDeviceAdapter`,每类设备只需完成一次驱动适配。
|
||
- **协议标准化**:统一抽象 Modbus-TCP、OPC-UA、HTTP/REST、MQTT、ONVIF、私有 TCP 等协议。
|
||
- **配置驱动上线**:新增同类设备无需改代码,只需在平台配置中心新增设备实例配置并绑定已有驱动。
|
||
- **可观测性统一**:设备状态统一汇总到 `DeviceRuntimeStatus`(在线/离线、延迟、错误码、最近心跳、告警级别)。
|
||
- **故障隔离**:单设备驱动异常不影响其他设备与调度主链路,驱动实例按租户/站点隔离。
|
||
|
||
### 5.4 Platform 平台能力补充(机器人群组与车队全生命周期管理)
|
||
|
||
Platform 提供车队级运维能力,支持 AGV 分区域、跨楼层、多车协作调度。
|
||
|
||
**核心能力:**
|
||
|
||
- **群组维度管理**:车队按楼层/区域/业务线分组,支持跨组协同任务。
|
||
- **硬件健康监控**:主控、驱动器、传感器、电池、定位模块的实时状态与趋势。
|
||
- **网络连通诊断**:链路质量、丢包、时延、断连重连次数、AP 切换质量。
|
||
- **OTA 升级**:远程固件/软件灰度发布、分批升级、回滚策略与版本基线管理。
|
||
- **批量操作**:休眠、唤醒、上线、下线、急停复位、一键任务清空/重派。
|
||
- **全生命周期闭环**:入网注册 → 运行监控 → 故障工单 → 维护保养 → 退役归档。
|
||
|
||
### 5.5 Platform 平台能力补充(业务场景模板化与可扩展机制)
|
||
|
||
Platform 将典型业务场景抽象为标准模板,支持开箱即用和后续扩展。
|
||
|
||
**内置模板(首批):**
|
||
|
||
- SPS 物料配送场景
|
||
- 电池 Pack 自动化产线场景
|
||
- 环线运行场景
|
||
- 点对点柔性搬运场景
|
||
|
||
**模板内容固化:**
|
||
|
||
- 调试参数(设备、车辆、节拍、阈值)
|
||
- 路径策略(寻路算法、权重、区域限制)
|
||
- 交通管制规则(路口互斥、让行策略)
|
||
- 任务流(任务编排、优先级、异常分支)
|
||
|
||
**扩展机制:**
|
||
|
||
- **配置扩展**:通过模板 DSL / JSON 配置新增场景,无需代码发布。
|
||
- **低代码扩展**:通过可视化编排器拼接任务流与策略块。
|
||
- **模板版本化**:模板支持版本、灰度、回滚、租户差异化覆盖。
|
||
- **模板市场化**:支持插件包导入导出(模板 + 设备驱动 + 参数基线)。
|
||
|
||
---
|
||
|
||
## 6. 共享内核分层
|
||
|
||
```mermaid
|
||
flowchart TB
|
||
subgraph 顶层["顶层(按端隔离)"]
|
||
L1A["Simple3 (CycleGUI + WebAPI Host)"]
|
||
L1B["MiGu.Server (ASP.NET Core + YARP)"]
|
||
L1B2["platform-vue (SPA, 管理员)"]
|
||
L1B3["rcsmonitor-vue (SPA, 运营)"]
|
||
end
|
||
|
||
subgraph 共享["共享业务层 (新增)"]
|
||
L2A["SimpleShared.Contracts<br/>(REST DTO + Swagger + WS 事件)"]
|
||
L2B["SimpleShared.Auth<br/>(JWT + RBAC + 权限码表)"]
|
||
L2C["SimpleShared.Config<br/>(配置模型 + 校验 + 下发协议)"]
|
||
L2D["SimpleShared.Persistence<br/>(EF Core + SQLite + 迁移)"]
|
||
L2E["SimpleShared.OpsCommand<br/>(运维命令白名单 + 审计 + 幂等)"]
|
||
L2F["SimpleShared.WebApiHost<br/>(Kestrel + Auth + Swagger 公共启动器)"]
|
||
end
|
||
|
||
subgraph 引擎["引擎与领域 (现有)"]
|
||
L3A["SimpleScheduler<br/>(DispatchLoop / Constraint / Recipe)"]
|
||
L3B["SimpleCore<br/>(站点 / 轨道 / Prop / Mission)"]
|
||
L3C["HttpClientHelper"]
|
||
L3D["Plugins (插件 DLL)"]
|
||
end
|
||
|
||
L1B2 -- "/admin/* + REST + WSS" --> L1B
|
||
L1B3 -- "/monitor/* + REST + WSS<br/>(scope=RCSMonitor)" --> L1B
|
||
|
||
L1A --> L2A
|
||
L1B --> L2A
|
||
L1A --> L2B
|
||
L1B --> L2B
|
||
L1A --> L2C
|
||
L1B --> L2C
|
||
L1A --> L2D
|
||
L1B --> L2D
|
||
L1A --> L2E
|
||
L1B --> L2E
|
||
L1A --> L2F
|
||
L1B --> L2F
|
||
|
||
L2C --> L2D
|
||
L2B --> L2D
|
||
|
||
L1A --> L3A
|
||
L1A --> L3B
|
||
L1A --> L3D
|
||
L1B --> L3B
|
||
L1B --> L3C
|
||
L3A --> L3B
|
||
```
|
||
|
||
### 新工程建议
|
||
|
||
| 工程 | 类型 | 关键职责 |
|
||
|------|------|----------|
|
||
| `SimpleShared.Contracts` | netstandard2.1 | REST DTO(POCO + DataAnnotations)+ OpenAPI/Swagger + WS 事件结构 + webVRender 桥接消息 |
|
||
| `SimpleShared.Auth` | net8.0 | IUserStore / IRoleStore / JwtIssuer / IPermissionEvaluator / 权限码表 / WidgetGrant |
|
||
| `SimpleShared.Config` | net8.0 | 强类型配置树 + 版本号 + Diff/校验 + 下发器 |
|
||
| `SimpleShared.Persistence` | net8.0 | EF Core 8 多 Provider 抽象(**SQLite / MySQL / PostgreSQL / SQL Server**)+ 迁移 + `DbProviderOptions` + 连接串构建器 + `WalSqliteOptions`(仅 SQLite) |
|
||
| `SimpleShared.OpsCommand` | net8.0 | 运维白名单命令、审计、幂等键、频次限流 |
|
||
| `SimpleShared.WebApiHost` | net8.0 | Kestrel 公共启动器:JWT 中间件 / Swagger / CORS / 健康检查 / 请求审计 |
|
||
| `MiGu.Server` | net8.0 ASP.NET Core | 业务 BFF + **YARP 反代 Simple3** + 静态托管两份 Vue dist;**启动时校验父进程为 Simple3,否则拒绝运行**(防误用) |
|
||
| `platform-vue` | Vue 3 + Vite + Pinia | 全功能套壳:复刻 Simple3 所有控件 |
|
||
| `rcsmonitor-vue` | Vue 3 + Vite + Pinia | 运营监控:按权限渲染,运维动作面板 |
|
||
| `packages/sl-controls`(pnpm workspace) | Vue 3 组件库 | Workspace3D(嵌 webVRender)/ 地图列表 / 任务表 / CAD 工具栏等共享组件 |
|
||
|
||
### 6.1 Platform Vue 控件复刻清单(与 Simple3 CycleGUI 对照)
|
||
|
||
| Simple3 CycleGUI 面板 | Vue 组件(位于 `sl-controls`) | 备注 |
|
||
|--------------------------|--------------------------------|------|
|
||
| 主菜单栏 / 工具栏 | `<AppShell>` 顶栏 + 侧栏 | platform-vue 全功能;rcsmonitor-vue 仅显示运营菜单 |
|
||
| Workspace 3D 视口 | `<Workspace3D>` | **iframe / Web Component 嵌入 Simple3 webVRender**;交互事件用 `postMessage` 桥接 |
|
||
| 地图面板(Sites / Tracks) | `<MapEditor>` + `<TrackTable>` | 表格 + 拓扑视图 |
|
||
| Car 面板 | `<CarPanel>` | 表格 + 表单 |
|
||
| Mission 面板 | `<MissionEditor>` | 任务流图 + 表单 |
|
||
| CAD 工具栏 | `<CadToolbar>` | 工具按钮组(按 `cad.tool.run` 显隐) |
|
||
| 字段编辑 / 图层 | `<FieldsLayers>` | 表单 + 树 |
|
||
| 状态 / 诊断 | `<StatesDashboard>` | ECharts 实时图 |
|
||
| 文件对话框 | `<ProjectFileDialog>` | 文件浏览器 + REST 上传/下载 |
|
||
| 运维动作面板 | `<OpsActionPanel>` | RCSMonitor 主战场,按 §5.1 白名单生成按钮 |
|
||
|
||
> 复刻策略:**先 1:1 对齐功能**,UI 风格交给前端工程师二次设计;接口协议统一在 `SimpleShared.Contracts` 内。
|
||
|
||
### 6.2 webVRender 嵌入方案
|
||
|
||
CycleGUI 的 `WebTerminal.Use(port, ico)` 已经原地提供:
|
||
- WebSocket 路由(驱动 Workspace 同步)
|
||
- 嵌入式 webVRender 页面(HTML + JS + WASM)
|
||
|
||
Vue 端集成方式(推荐 iframe,最简单稳定):
|
||
|
||
```vue
|
||
<!-- packages/sl-controls/src/Workspace3D.vue (简化示意) -->
|
||
<template>
|
||
<iframe
|
||
ref="frame"
|
||
:src="vrUrl"
|
||
class="workspace-3d"
|
||
@load="onReady" />
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { computed, ref } from 'vue';
|
||
const props = defineProps<{
|
||
host: string; // e.g. host:8223
|
||
scope: 'Platform' | 'RCSMonitor';
|
||
token: string; // 透传 JWT
|
||
readOnly?: boolean;
|
||
}>();
|
||
const emit = defineEmits<{
|
||
(e: 'pick', wp: { x: number; y: number }): void;
|
||
(e: 'select', names: string[]): void;
|
||
}>();
|
||
const frame = ref<HTMLIFrameElement>();
|
||
const vrUrl = computed(() =>
|
||
`http://${props.host}/?scope=${props.scope}&token=${encodeURIComponent(props.token)}&ro=${props.readOnly ? 1 : 0}`);
|
||
function onReady() {
|
||
window.addEventListener('message', (ev) => {
|
||
if (ev.source !== frame.value?.contentWindow) return;
|
||
const msg = ev.data;
|
||
if (msg.type === 'workspace.pick') emit('pick', msg.payload);
|
||
else if (msg.type === 'workspace.select') emit('select', msg.payload);
|
||
});
|
||
}
|
||
</script>
|
||
```
|
||
|
||
`Simple3/Rendering/SimpleSceneRenderer.cs` 端按 `scope` 和 `ro` 控制:
|
||
- `scope=RCSMonitor` 或 `ro=1` → 禁用编辑工具(不响应 `SelectObject`/`GetPosition` 中的拖动)
|
||
- 通过 `postMessage` 向 iframe 父页面回传选择/点击事件
|
||
|
||
如未来需要更深的双向集成(如自定义 Vue 弹层叠在 3D 视口上),可升级到 Web Component(`<sl-workspace3d>`),但 iframe 已能覆盖 95% 场景。
|
||
|
||
### 6.3 YARP 反向代理配置(示例)
|
||
|
||
```csharp
|
||
// MiGu.Server / Program.cs
|
||
var builder = WebApplication.CreateBuilder(args);
|
||
|
||
builder.Services.AddReverseProxy()
|
||
.LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"))
|
||
.AddTransforms(ctx =>
|
||
{
|
||
// 透传当前 JWT 的 userId / scope 给 Simple3
|
||
ctx.AddRequestTransform(async tc =>
|
||
{
|
||
var ident = tc.HttpContext.User;
|
||
tc.ProxyRequest.Headers.Add("X-On-Behalf-Of", ident.FindFirst("sub")?.Value ?? "");
|
||
tc.ProxyRequest.Headers.Add("X-Scope", ident.FindFirst("scope")?.Value ?? "");
|
||
tc.ProxyRequest.Headers.Add("X-Svc-Token", SvcTokenIssuer.Current());
|
||
});
|
||
});
|
||
|
||
builder.Services
|
||
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||
.AddJwtBearer(opt => opt.TokenValidationParameters = JwtTokenOptions.Default);
|
||
|
||
var app = builder.Build();
|
||
app.UseAuthentication();
|
||
app.UseAuthorization();
|
||
|
||
// 关键:scope=RCSMonitor 的请求只能命中 /api/sl/ops/* 白名单
|
||
app.MapReverseProxy(pipe => pipe.Use(async (ctx, next) =>
|
||
{
|
||
var scope = ctx.User.FindFirst("scope")?.Value;
|
||
var path = ctx.Request.Path.Value ?? "";
|
||
if (scope == "RCSMonitor" && !path.StartsWith("/api/sl/ops/"))
|
||
{
|
||
ctx.Response.StatusCode = StatusCodes.Status403Forbidden;
|
||
await ctx.Response.WriteAsync("Scope RCSMonitor cannot access this endpoint");
|
||
return;
|
||
}
|
||
await next();
|
||
}));
|
||
|
||
app.UseStaticFiles();
|
||
app.MapWhen(c => c.Request.Path.StartsWithSegments("/admin"),
|
||
sub => sub.UseStaticFiles().UseSpa(s => s.Options.SourcePath = "frontends/platform-vue/dist"));
|
||
app.MapWhen(c => c.Request.Path.StartsWithSegments("/monitor"),
|
||
sub => sub.UseStaticFiles().UseSpa(s => s.Options.SourcePath = "frontends/rcsmonitor-vue/dist"));
|
||
|
||
app.Run();
|
||
```
|
||
|
||
`appsettings.json` 中的 YARP 路由:
|
||
|
||
```json
|
||
{
|
||
"ReverseProxy": {
|
||
"Routes": {
|
||
"sl-route": {
|
||
"ClusterId": "sl-cluster",
|
||
"Match": { "Path": "/api/sl/{**catch-all}" },
|
||
"Transforms": [
|
||
{ "PathRemovePrefix": "/api/sl" },
|
||
{ "RequestHeader": "Host", "Set": "" }
|
||
]
|
||
}
|
||
},
|
||
"Clusters": {
|
||
"sl-cluster": {
|
||
"Destinations": {
|
||
"sl1": { "Address": "http://127.0.0.1:7001/" }
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 7. 数据库与高可用(多 Provider)
|
||
|
||
只剩两个逻辑库(`simple_main` / `platform`);持久层基于 **EF Core**,**通过 Provider 切换底层数据库**。**SQLite 是默认与边缘单机首选**,企业级或已有 IT 基础设施现场可平滑切到 **MySQL / PostgreSQL / SQL Server**;高可用方案随 Provider 不同。
|
||
|
||
### 7.1 持久层抽象(EF Core Provider 矩阵)
|
||
|
||
```mermaid
|
||
flowchart TB
|
||
subgraph App["应用代码 (Simple3 / MiGu.Server)"]
|
||
DOM["领域服务 / Repository"]
|
||
EFC["EF Core 8 DbContext"]
|
||
OPT["DbProviderOptions<br/>{ provider, conn, ha }"]
|
||
end
|
||
|
||
subgraph SharedLayer["SimpleShared.Persistence"]
|
||
BLD["ConnectionStringBuilder"]
|
||
MIG["Migrations<br/>(SQLite/MySQL/Pg/MSSQL 各一套)"]
|
||
DI["AddSimplePersistence(...)<br/>(Provider 注入)"]
|
||
end
|
||
|
||
subgraph Providers["EF Core Provider"]
|
||
P1["Microsoft.EntityFrameworkCore.Sqlite"]
|
||
P2["Pomelo.EntityFrameworkCore.MySql"]
|
||
P3["Npgsql.EntityFrameworkCore.PostgreSQL"]
|
||
P4["Microsoft.EntityFrameworkCore.SqlServer"]
|
||
end
|
||
|
||
DOM --> EFC
|
||
EFC --> OPT
|
||
OPT --> DI
|
||
DI --> P1
|
||
DI --> P2
|
||
DI --> P3
|
||
DI --> P4
|
||
DI --> MIG
|
||
DI --> BLD
|
||
|
||
P1 -. file .-> S1[(SQLite 文件<br/>+ WAL)]
|
||
P2 -. tcp .-> S2[(MySQL 8.x)]
|
||
P3 -. tcp .-> S3[(PostgreSQL 14+)]
|
||
P4 -. tcp .-> S4[(SQL Server 2019+)]
|
||
```
|
||
|
||
**抽象核心:**
|
||
|
||
- 所有 `DbContext`(如 `MainDbContext` / `PlatformDbContext`)**不感知 Provider**,使用通用 LINQ + 注解;少量数据库特性(如 `JSON` 列、`uuid` 主键)由 `IDbProviderSpecifics` 抽象出三套实现。
|
||
- **迁移按 Provider 独立维护**:`Migrations/Sqlite`、`Migrations/MySql`、`Migrations/Npgsql`、`Migrations/SqlServer`;CI 跑全部矩阵保证不偏漂。
|
||
- **运行期切换**:仅启动期生效,通过 `simple.json` / `Platform.appsettings.json` 的 `database.provider` 字段决定加载哪一个;不支持热切。
|
||
- **测试矩阵**:CI 用 Testcontainers 起对应 DB 跑端到端集成测试。
|
||
|
||
### 7.2 各库存储内容(与 Provider 无关)
|
||
|
||
| 逻辑库 | 拥有进程 | 主要表/数据 |
|
||
|--------|----------|-------------|
|
||
| **simple_main** | Simple3 | Maps, Sites, Tracks, SpecialProps, Missions, Cars, Plugins, DesignAuditLog, OpsAuditLog, LocalUsers, RunModeHistory |
|
||
| **platform** | Platform | Users, Roles, RolePermissions, WidgetGrants, SystemConfig, ExternalAdapters, RoutingPolicies, VehicleMaintenancePolicies, ChargePolicies, TaskAllocationPolicies, TrafficRules, Locations, Inventory, OpsLogs(含 RCSMonitor 来源), Annotations, Snapshots, Versions, CustomWidgets |
|
||
|
||
> 原 v1.2 中的 `rcsmonitor_local` 取消;其表(OpsLogs / Annotations / Snapshots / WidgetLayoutCache)合并到 `platform`,加 `source='RCSMonitor'` 字段区分。
|
||
> Provider 不同时,逻辑表名一致;物理实现差异(`uuid` vs `binary(16)`、`json` vs `nvarchar(max)`、自增策略等)由迁移文件适配。
|
||
|
||
### 7.3 SQLite + ROSE HA(默认 / 边缘单机)
|
||
|
||
```mermaid
|
||
flowchart TB
|
||
subgraph A["主节点 NODE-A (Active)"]
|
||
SL_A["Simple3.exe"]
|
||
PL_A["MiGu.Server.exe"]
|
||
D_A[("受 ROSE 保护盘 R:\<br/>simple_main.db<br/>platform.db<br/>(WAL)")]
|
||
end
|
||
subgraph B["备节点 NODE-B (Standby)"]
|
||
SL_B["Simple3.exe (suspended)"]
|
||
PL_B["MiGu.Server.exe (suspended)"]
|
||
D_B[("ROSE 镜像盘 R:\")]
|
||
end
|
||
VIP(("浮动 IP / VIP"))
|
||
Client["客户端"]
|
||
Client --> VIP --> SL_A
|
||
A <-- "ROSE 块级镜像 + 心跳" --> B
|
||
A -. 故障切换 .-> B
|
||
```
|
||
|
||
**适用场景**:边缘工控机 / 单机现场 / IT 基础设施薄弱 / 初装版本。
|
||
|
||
**关键约束:**
|
||
|
||
| 约束 | 落地做法 |
|
||
|------|----------|
|
||
| **数据文件必须放 ROSE 受保护盘** | 两端 `Configuration` 中数据库路径统一指向 `%SIMPLE_DATA_ROOT%`(默认 `R:\SimpleData\`) |
|
||
| **同一时刻只能一个节点写库** | ROSE 切换前后保证只有 Active 节点起服务;备节点服务进程**默认禁用自启** |
|
||
| **关闭跨进程共享缓存** | 连接串 `Cache=Private; Mode=ReadWriteCreate; Pooling=true; Default Timeout=30` |
|
||
| **支持优雅停机** | 实现 `IHostedService.StopAsync`,等 WS 排空 + Checkpoint(WAL) |
|
||
| **客户端通过 VIP 访问** | Vue 与车端均连浮动 IP;WS 自动重连 < 5s |
|
||
| **Web-Enabled 与 ROSE 强绑定** | 双机热备只在 Web-Enabled 模式下有意义 |
|
||
| **切换演练** | `tools/ha/failover-drill.ps1` |
|
||
|
||
**ROSE 资源建议命名:**
|
||
|
||
| 资源 | 类型 | 依赖 |
|
||
|------|------|------|
|
||
| `RES_DISK_R` | Mirror Disk | — |
|
||
| `RES_VIP_LAN` | Virtual IP | RES_DISK_R |
|
||
| `RES_SVC_SL` | Service: Simple3 (Web-Enabled) | RES_DISK_R, RES_VIP_LAN |
|
||
| `RES_SVC_PL` | Service: MiGu.Server | RES_DISK_R, RES_VIP_LAN, RES_SVC_SL |
|
||
| `RES_SCRIPT_CHK` | 数据库健康检查脚本 | RES_DISK_R |
|
||
|
||
**RTO / RPO**:RTO < 60s,RPO ≈ 0(块级镜像)。
|
||
|
||
### 7.4 MySQL + InnoDB Cluster / MGR
|
||
|
||
```mermaid
|
||
flowchart TB
|
||
subgraph App["应用层 (VIP + 重试)"]
|
||
SL["Simple3.exe"]
|
||
PL["MiGu.Server.exe"]
|
||
end
|
||
subgraph Router["MySQL Router (或 ProxySQL)"]
|
||
R1["VIP :6446 (RW)"]
|
||
R2["VIP :6447 (RO)"]
|
||
end
|
||
subgraph Cluster["InnoDB Cluster (MGR, group_replication)"]
|
||
M1[("Primary<br/>node1")]
|
||
M2[("Secondary<br/>node2")]
|
||
M3[("Secondary<br/>node3")]
|
||
M1 <-- "Group Replication" --> M2
|
||
M2 <-- "Group Replication" --> M3
|
||
M1 <-- "Group Replication" --> M3
|
||
end
|
||
SL --> R1
|
||
PL --> R1
|
||
R1 --> M1
|
||
R2 --> M2
|
||
R2 --> M3
|
||
```
|
||
|
||
**适用场景**:现场已有 MySQL DBA / 中等规模 / Linux 优先 / 多读副本需求。
|
||
|
||
**关键说明:**
|
||
|
||
- **EF Core Provider**:`Pomelo.EntityFrameworkCore.MySql`(对 MySQL 8.x / MariaDB 10.x 兼容性最好)。
|
||
- **HA 形态**:推荐 **InnoDB Cluster(基于 MySQL Group Replication + MySQL Router)** 三节点,单点故障自动重选主;老版本 MySQL 可降级用 **MHA / Orchestrator + 半同步复制**。
|
||
- **连接配置**:应用连 MySQL Router 的 RW 端口(`:6446`),由 Router 自动路由到当前 Primary;只读分析查询可走 RO 端口(`:6447`)。
|
||
- **字符集**:统一 `utf8mb4` + `utf8mb4_0900_ai_ci`;EF Core 配 `CharSet.Utf8Mb4`。
|
||
- **写入隔离级别**:`READ COMMITTED`(避免 RR 下的间隙锁导致死锁);MGR 要求 InnoDB 引擎、主键必填。
|
||
- **审计/慢日志**:开 `general_log` + `slow_query_log`;MiGu.Server 启动期校验。
|
||
- **备份**:每天 `mysqldump --single-transaction` 或 XtraBackup 到 NAS;保留 30 天 + Binlog。
|
||
- **RTO / RPO**:RTO ≈ 10–30s(MGR 自动选主);RPO ≈ 0(半同步 / Group Replication 强一致)。
|
||
|
||
### 7.5 PostgreSQL + Patroni / 流复制
|
||
|
||
```mermaid
|
||
flowchart TB
|
||
subgraph App["应用层"]
|
||
SL["Simple3.exe"]
|
||
PL["MiGu.Server.exe"]
|
||
end
|
||
subgraph LB["HAProxy / PgBouncer"]
|
||
H1["VIP :5432 (RW → leader)"]
|
||
H2["VIP :5433 (RO → replicas)"]
|
||
end
|
||
subgraph Cluster["Patroni 集群"]
|
||
P1[("Leader<br/>pg1")]
|
||
P2[("Replica<br/>pg2")]
|
||
P3[("Replica<br/>pg3")]
|
||
DCS[("DCS<br/>etcd / Consul / ZooKeeper")]
|
||
P1 -- "流复制" --> P2
|
||
P1 -- "流复制" --> P3
|
||
P1 <-- "leader lease" --> DCS
|
||
P2 <-- "heartbeat" --> DCS
|
||
P3 <-- "heartbeat" --> DCS
|
||
end
|
||
SL --> H1
|
||
PL --> H1
|
||
H1 --> P1
|
||
H2 --> P2
|
||
H2 --> P3
|
||
```
|
||
|
||
**适用场景**:复杂查询 / GIS(PostGIS)/ JSON 重场景 / 已有 Postgres DBA / 长期数据归档与分析。
|
||
|
||
**关键说明:**
|
||
|
||
- **EF Core Provider**:`Npgsql.EntityFrameworkCore.PostgreSQL`;可直接使用 `uuid` / `jsonb` / `tstzrange` 等原生类型。
|
||
- **HA 形态**:推荐 **Patroni + etcd(或 Consul)+ 流复制**;HAProxy / PgBouncer 提供单一 RW VIP。
|
||
- **同步策略**:`synchronous_commit = remote_apply` + `synchronous_standby_names = 'ANY 1 (pg2,pg3)'`,写至少一个备机确认,兼顾性能与 RPO≈0。
|
||
- **PgBouncer**:建议事务级(`pool_mode=transaction`),MiGu.Server 并发连接通过 PgBouncer 复用;注意 EF Core 显式事务跨多个语句时不要踩 transaction 模式陷阱。
|
||
- **JSONB 利用**:`SystemConfig` / `CustomWidget.SchemaJson` 等列直接用 `jsonb` + GIN 索引,比 SQLite 的 TEXT/JSON 检索强很多。
|
||
- **备份**:`pg_basebackup` + WAL 归档(`archive_command` → NAS / S3 / pgBackRest)。
|
||
- **RTO / RPO**:RTO ≈ 10–30s(Patroni 自动 failover);RPO ≈ 0(同步流复制)。
|
||
|
||
### 7.6 SQL Server + Always On Availability Groups
|
||
|
||
```mermaid
|
||
flowchart TB
|
||
subgraph App["应用层"]
|
||
SL["Simple3.exe"]
|
||
PL["MiGu.Server.exe"]
|
||
end
|
||
subgraph Listener["AG Listener (DNS + VIP)"]
|
||
L1["VIP :1433 (RW)"]
|
||
L2["ReadOnly Routing"]
|
||
end
|
||
subgraph Cluster["WSFC + Always On AG"]
|
||
AG1[("Primary<br/>sql1")]
|
||
AG2[("Secondary<br/>sql2 同步提交")]
|
||
AG3[("Secondary<br/>sql3 异步提交/可读")]
|
||
AG1 -- "同步提交" --> AG2
|
||
AG1 -- "异步提交" --> AG3
|
||
WSFC[/"Windows Server Failover<br/>Cluster (Quorum)"/]
|
||
AG1 --- WSFC
|
||
AG2 --- WSFC
|
||
AG3 --- WSFC
|
||
end
|
||
SL --> L1
|
||
PL --> L1
|
||
L2 --> AG3
|
||
```
|
||
|
||
**适用场景**:Windows 工控/服务器场景 / 已有 SQL Server 许可与 DBA / 与企业 AD/SSO 集成。
|
||
|
||
**关键说明:**
|
||
|
||
- **EF Core Provider**:`Microsoft.EntityFrameworkCore.SqlServer`;支持 SQL Server 2019+(建议 Enterprise 版以启用同步提交副本数 ≥3 + Read-Only Routing)。Standard 版可降级为 2 副本基本可用性组。
|
||
- **HA 形态**:**WSFC(Windows Server Failover Cluster)+ Always On Availability Groups**;通过 **AG Listener** 暴露统一虚拟名/VIP,客户端连 Listener 名即可。
|
||
- **同步策略**:核心库(`platform` / `simple_main`)配 1 个同步提交副本(RPO=0),1–N 个异步副本(可读分析)。
|
||
- **认证**:建议混合身份认证;MiGu.Server 用 SQL Login,Simple3 桌面端可走 Windows 集成认证。
|
||
- **TempDB**:每节点分摊;MultipleActiveResultSets(MARS)建议关闭,EF Core 已能避免。
|
||
- **备份**:`BACKUP DATABASE ... WITH COMPRESSION` + 事务日志备份每 15min;保留策略与公司 IT 一致。
|
||
- **RTO / RPO**:RTO ≈ 10–30s(AG 自动 failover);RPO ≈ 0(同步提交副本)。
|
||
|
||
### 7.7 选型矩阵
|
||
|
||
| 维度 | SQLite + ROSE | MySQL InnoDB Cluster | PostgreSQL Patroni | SQL Server Always On |
|
||
|------|---------------|----------------------|---------------------|----------------------|
|
||
| **典型现场** | 边缘工控机 / 单机 | 中型现场 / Linux 优先 / 已有 MySQL DBA | 复杂分析 / GIS / 已有 PG DBA | Windows 企业环境 / 已有 SQL Server |
|
||
| **并发写吞吐** | 低(千级 TPS) | 高(万级) | 高(万级) | 高(万级) |
|
||
| **节点数** | 2(主备) | 3+(推荐 3) | 3+ | 2–3(含见证或共享磁盘见证) |
|
||
| **复制粒度** | 块级磁盘镜像(ROSE) | Group Replication 行级 | WAL 流复制 | 同步/异步提交 |
|
||
| **RTO** | < 60s | 10–30s | 10–30s | 10–30s |
|
||
| **RPO** | ≈0(块级实时) | ≈0(强一致) | ≈0(同步) | ≈0(同步提交副本) |
|
||
| **运维复杂度** | 低(ROSE 包办) | 中(要会 MGR)| 中–高(要会 Patroni + DCS) | 中(要熟 WSFC) |
|
||
| **跨机房 / 多活** | 不支持 | 支持(多组复制 + 路由) | 支持(流复制多机房) | 支持(分布式 AG) |
|
||
| **额外依赖** | ROSE HA 软件 | MySQL Router / ProxySQL | etcd/Consul + HAProxy/PgBouncer | Windows Server + WSFC + AD |
|
||
| **License 成本** | 仅 ROSE 授权 | 开源(社区版) / 商业支持可选 | 开源 | SQL Server License(Enterprise 较贵) |
|
||
| **JSON / 复杂查询** | 弱(TEXT/JSON1)| 中(5.7+ JSON) | **强(jsonb + GIN)** | 中(NVARCHAR + JSON_VALUE) |
|
||
| **GIS** | 弱(SpatiaLite) | 中 | **强(PostGIS)** | 强(Spatial) |
|
||
|
||
> **现场决策建议**:默认提供 SQLite 版本(开箱即用 + ROSE 双机)。客户已有数据库基础设施时,按团队最熟悉的栈选 MySQL / PostgreSQL / SQL Server;产品仅维护 4 套迁移与一份连接配置规范。
|
||
|
||
### 7.8 配置示例(`simple.json` / `appsettings.json`)
|
||
|
||
#### 7.8.1 SQLite(默认)
|
||
|
||
```json
|
||
{
|
||
"database": {
|
||
"provider": "Sqlite",
|
||
"simple_main": {
|
||
"dataSource": "%SIMPLE_DATA_ROOT%/simple_main.db",
|
||
"extra": "Cache=Private;Mode=ReadWriteCreate;Pooling=true;Default Timeout=30"
|
||
},
|
||
"platform": {
|
||
"dataSource": "%SIMPLE_DATA_ROOT%/platform.db",
|
||
"extra": "Cache=Private;Mode=ReadWriteCreate;Pooling=true;Default Timeout=30"
|
||
},
|
||
"ha": { "mode": "ROSE", "protectedDisk": "R:\\SimpleData" }
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 7.8.2 MySQL
|
||
|
||
```json
|
||
{
|
||
"database": {
|
||
"provider": "MySql",
|
||
"simple_main": {
|
||
"host": "rcs-mysql.lan",
|
||
"port": 6446,
|
||
"database": "simple_main",
|
||
"user": "simple_app",
|
||
"password": "${SECRET_MYSQL_PWD}",
|
||
"extra": "SslMode=Required;CharSet=utf8mb4;DefaultCommandTimeout=30"
|
||
},
|
||
"platform": {
|
||
"host": "rcs-mysql.lan",
|
||
"port": 6446,
|
||
"database": "simple_platform",
|
||
"user": "simple_app",
|
||
"password": "${SECRET_MYSQL_PWD}"
|
||
},
|
||
"ha": { "mode": "InnoDBCluster", "router": "rcs-mysql.lan:6446" }
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 7.8.3 PostgreSQL
|
||
|
||
```json
|
||
{
|
||
"database": {
|
||
"provider": "Npgsql",
|
||
"simple_main": {
|
||
"host": "rcs-pg.lan",
|
||
"port": 5432,
|
||
"database": "simple_main",
|
||
"user": "simple_app",
|
||
"password": "${SECRET_PG_PWD}",
|
||
"extra": "Ssl Mode=Require;Pooling=true;Maximum Pool Size=80;Command Timeout=30"
|
||
},
|
||
"platform": {
|
||
"host": "rcs-pg.lan",
|
||
"port": 5432,
|
||
"database": "simple_platform",
|
||
"user": "simple_app",
|
||
"password": "${SECRET_PG_PWD}"
|
||
},
|
||
"ha": { "mode": "Patroni", "vip": "rcs-pg.lan", "readReplicaPort": 5433 }
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 7.8.4 SQL Server
|
||
|
||
```json
|
||
{
|
||
"database": {
|
||
"provider": "SqlServer",
|
||
"simple_main": {
|
||
"server": "tcp:rcs-ag.lan,1433",
|
||
"database": "simple_main",
|
||
"user": "simple_app",
|
||
"password": "${SECRET_MSSQL_PWD}",
|
||
"extra": "Encrypt=True;TrustServerCertificate=False;MultiSubnetFailover=True;Application Name=Simple3"
|
||
},
|
||
"platform": {
|
||
"server": "tcp:rcs-ag.lan,1433",
|
||
"database": "simple_platform",
|
||
"user": "simple_app",
|
||
"password": "${SECRET_MSSQL_PWD}",
|
||
"extra": "Encrypt=True;TrustServerCertificate=False;MultiSubnetFailover=True"
|
||
},
|
||
"ha": { "mode": "AlwaysOnAG", "listener": "rcs-ag.lan" }
|
||
}
|
||
}
|
||
```
|
||
|
||
> **密码注入**:`${SECRET_*}` 由 `IConfiguration` 的环境变量 / Azure Key Vault / DPAPI 加密文件提供;明文绝不入仓库。
|
||
|
||
### 7.9 跨 Provider 迁移与数据搬迁
|
||
|
||
- **首次部署切换**:通过 `tools/db/migrate.ps1 --from=Sqlite --to=Npgsql` 一键导出/导入;底层使用 EF Core `IModel` 反序列化每张表后批量写入目标。
|
||
- **滚动升级**:不支持热切;停服窗口内执行迁移;保留旧 SQLite 文件作回退包。
|
||
- **CI 守护**:每个迁移 PR 必须通过四套 Provider 的迁移 + 端到端测试(Testcontainers)。
|
||
- **数据类型差异**:UUID(SQLite TEXT / MySQL CHAR(36) / Pg uuid / MSSQL UNIQUEIDENTIFIER)、JSON(SQLite TEXT JSON1 / MySQL JSON / Pg jsonb / MSSQL NVARCHAR JSON)由 `IDbProviderSpecifics` 抽出三套配置;应用层无感知。
|
||
|
||
---
|
||
|
||
## 8. 用户 / 权限模型(含控件级权限)
|
||
|
||
```mermaid
|
||
classDiagram
|
||
class User {
|
||
+Guid Id
|
||
+string Username
|
||
+string PasswordHash
|
||
+string Email
|
||
+bool Enabled
|
||
+DateTime LastLogin
|
||
}
|
||
class Role {
|
||
+Guid Id
|
||
+string Name
|
||
+string Scope
|
||
}
|
||
class Permission {
|
||
+string Code
|
||
+string Resource
|
||
}
|
||
class WidgetGrant {
|
||
+string WidgetId
|
||
+string Visibility
|
||
}
|
||
class Tenant {
|
||
+Guid Id
|
||
+string Name
|
||
}
|
||
User "1" --> "*" Role : assigned
|
||
Role "1" --> "*" Permission : grants
|
||
Role "1" --> "*" WidgetGrant : grants
|
||
Tenant "1" --> "*" User
|
||
User -- LoginSession
|
||
LoginSession : +string JwtId
|
||
LoginSession : +DateTime IssuedAt
|
||
LoginSession : +string ClientApp
|
||
LoginSession : +string Scope
|
||
```
|
||
|
||
**落地四件套:**
|
||
|
||
1. **认证**:`SimpleShared.Auth` 提供 `JwtIssuer`;Web-Enabled 时 MiGu.Server 签发;Desktop-Only 时 Simple3 本地签发短期 Token(24h)。
|
||
2. **授权**:所有 WebAPI + WS 调用走 `IPermissionEvaluator`;权限码 `<area>.<action>`。
|
||
3. **范围(Scope)**:`Lite` / `Platform` / `RCSMonitor` / `*`;同一用户在不同端可用集合不同。Vue 端登录时由前端代码根据访问路径自动带入 `scope`(`/admin/*` → `Platform`,`/monitor/*` → `RCSMonitor`)。
|
||
4. **控件级权限**:除 `Permission` 外,角色还可关联 `WidgetGrant`,每个 `WidgetId` 三档可见性:
|
||
- `hidden`:根本不渲染
|
||
- `readonly`:渲染但禁用交互
|
||
- `interactive`:完全可交互(仍受操作权限码二次校验)
|
||
|
||
### 8.1 RCSMonitor 登录与权限拉取
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant U as 运营用户
|
||
participant RV as rcsmonitor-vue
|
||
participant P as MiGu.Server
|
||
participant L as Simple3 (YARP 后侧)
|
||
participant DBp as platform.db
|
||
|
||
U->>RV: 访问 https://host:8080/monitor
|
||
RV->>P: GET /monitor/index.html (静态)
|
||
P-->>RV: 200 OK
|
||
U->>RV: 输入账号密码
|
||
RV->>P: POST /api/auth/login {scope=RCSMonitor}
|
||
P->>P: 校验账号 + 计算 EffectivePermissions
|
||
P->>DBp: 写 LoginSession
|
||
P-->>RV: { token, user, effectivePermissions }
|
||
RV->>RV: 按 visibleWidgets / allowedOps 裁剪 UI
|
||
RV->>P: GET /api/sl/projection/map (token, scope=RCSMonitor)
|
||
P->>P: YARP 中间件: scope 合法? path 在 /ops/* 之外? 投影类不拦截
|
||
P->>L: GET /api/projection/map (X-On-Behalf-Of, X-Scope, X-Svc-Token)
|
||
L-->>P: 投影
|
||
P-->>RV: 投影
|
||
RV->>P: WS /ws/events (token)
|
||
P->>L: WS /ws/events (svc identity)
|
||
L-->>P: 推送
|
||
P-->>RV: 转发
|
||
```
|
||
|
||
---
|
||
|
||
## 9. 平台配置中心
|
||
|
||
覆盖以下维度:
|
||
|
||
| 配置维度 | 说明 |
|
||
|----------|------|
|
||
| 系统级配置 | 运行参数、日志策略、安全策略 |
|
||
| 外部系统对接 | MES/WMS/RCS 等标准接口配置 |
|
||
| 路径规划策略 | 算法选择、权重、避障规则、区域限速 |
|
||
| 车辆维护策略 | 电量阈值、故障上报、自动报修 |
|
||
| 充电逻辑 | 充电优先级、空闲充电、任务中断充电 |
|
||
| 任务分配机制 | 负载均衡、就近分配、优先级调度 |
|
||
| 交通管制规则 | 路口策略、区域互斥、动态让行 |
|
||
| 权限与角色管理 | 多用户、功能权限控制、控件授权 |
|
||
| 第三方设备统一接入与管理 | 电梯/门禁/充电桩/AP/交换机/摄像头/读码器/PLC 统一注册、配置、监控、告警与审计 |
|
||
| 机器人群组与车队全生命周期管理 | 分区域/跨楼层/多车协作;硬件监控、网络诊断、OTA、批量操作、维护闭环 |
|
||
| 业务场景模板化与扩展机制 | SPS、Pack 产线、环线、点对点模板;参数/路径/交管/任务流固化;配置/低代码扩展 |
|
||
| 库位管理 | 出入库管理、库存管理、库位可视化 |
|
||
| 运营维护 | 调度回放、日志管理、版本维护 |
|
||
| 自定义控件管理 | 呼叫/展示界面可自由定义(platform-vue + rcsmonitor-vue 双渲染器) |
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
subgraph PlatformVue["platform-vue 配置中心"]
|
||
UI1[系统级]
|
||
UI2[外部对接]
|
||
UI3[路径规划]
|
||
UI4[车辆维护]
|
||
UI5[充电]
|
||
UI6[任务分配]
|
||
UI7[交通管制]
|
||
UI8[权限/角色/控件]
|
||
UI9[库位/库存]
|
||
UI10[运营/回放]
|
||
UI11[自定义控件]
|
||
end
|
||
|
||
subgraph CC["ConfigCenter (MiGu.Server)"]
|
||
Sch[Schema 注册表]
|
||
Ver[版本/审计]
|
||
Val[校验器]
|
||
Pub[发布器]
|
||
end
|
||
|
||
UI1 --> Sch
|
||
UI2 --> Sch
|
||
UI3 --> Sch
|
||
UI4 --> Sch
|
||
UI5 --> Sch
|
||
UI6 --> Sch
|
||
UI7 --> Sch
|
||
UI8 --> Sch
|
||
UI9 --> Sch
|
||
UI10 --> Sch
|
||
UI11 --> Sch
|
||
Sch --> Val --> Ver --> Pub
|
||
|
||
Pub -- "REST PUT /api/sl/config/{section} (via YARP)" --> SL["Simple3 (主服务)"]
|
||
Pub -- "WS broadcast: config.updated" --> RMVue["rcsmonitor-vue"]
|
||
Pub -- "WS broadcast: config.updated" --> AdminVue["其他在线 platform-vue"]
|
||
```
|
||
|
||
### 配置强类型骨架(C# 示例)
|
||
|
||
```csharp
|
||
public record SystemConfig(int DispatchLoopHz, LogPolicy Log, SecurityPolicy Security);
|
||
|
||
public record ExternalIntegrations(List<MesEndpoint> Mes, List<WmsEndpoint> Wms, List<RcsEndpoint> Rcs);
|
||
|
||
public record RoutingPolicy(
|
||
string Algorithm,
|
||
Dictionary<string, double> Weights,
|
||
List<AvoidanceRule> Avoidance,
|
||
List<ZoneSpeedLimit> ZoneSpeedLimits);
|
||
|
||
public record VehicleMaintenancePolicy(
|
||
double LowBatteryThreshold,
|
||
double CriticalBatteryThreshold,
|
||
FaultReportPolicy FaultReport,
|
||
AutoRepairPolicy AutoRepair);
|
||
|
||
public record ChargePolicy(bool AllowMidTaskCharge, double IdleChargeAfterSec, List<ChargePriorityRule> Priority);
|
||
|
||
public record TaskAllocationPolicy(AllocationMode Mode, bool LoadBalance, int MaxQueuePerCar);
|
||
|
||
public record TrafficRule(List<IntersectionPolicy> Intersections, List<ZoneMutex> Mutex, List<DynamicYield> Yields);
|
||
|
||
public record DeviceManagementConfig(
|
||
List<DeviceDriverBinding> Drivers,
|
||
List<DeviceInstance> Devices,
|
||
DeviceHealthPolicy HealthPolicy,
|
||
AlarmPolicy AlarmPolicy);
|
||
|
||
public record FleetLifecycleConfig(
|
||
List<FleetGroup> Groups,
|
||
OtaPolicy Ota,
|
||
BatchOpsPolicy BatchOps,
|
||
NetworkDiagPolicy NetworkDiag);
|
||
|
||
public record ScenarioTemplateConfig(
|
||
List<ScenarioTemplate> Templates,
|
||
TemplateDslPolicy DslPolicy,
|
||
LowCodePolicy LowCode,
|
||
TemplateVersionPolicy VersionPolicy);
|
||
|
||
public record LocationManagement(List<Location> Locations, List<InventoryRule> InventoryRules);
|
||
|
||
public record OpsConfig(PlaybackPolicy Playback, LogRetention LogRetention, VersionPolicy Version);
|
||
|
||
public record CustomWidget(string Id, string Name, string SchemaJson, string LayoutJson, List<string> BindToScopes);
|
||
|
||
public record EffectivePermissions(
|
||
string UserId,
|
||
int Version,
|
||
List<string> AllowedOps,
|
||
List<WidgetGrantDto> VisibleWidgets);
|
||
```
|
||
|
||
**发布机制:** Schema → 校验 → 版本 → 灰度 → 全量;MiGu.Server 通过 YARP `PUT /api/sl/config/{section}` 推到 Simple3,主服务原子切换 + ack;失败自动回滚,WS `config.rollback` 广播。
|
||
|
||
---
|
||
|
||
## 10. 关键交互序列
|
||
|
||
### 10.1 启动登录 + Web-Enabled 三端建链
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant U as 用户
|
||
participant L as Simple3 (CycleGUI)
|
||
participant BL as BootLoginPanel
|
||
participant K as Kestrel (WebAPI)
|
||
participant P as MiGu.Server (YARP)
|
||
participant V as platform-vue
|
||
participant RV as rcsmonitor-vue
|
||
|
||
U->>L: 启动 Simple3.exe
|
||
L->>L: 读取 simple.json
|
||
alt rememberRunMode = true
|
||
L->>L: 直接采用 runMode (仍鉴权)
|
||
else
|
||
L->>BL: 弹出登录窗
|
||
U->>BL: 输入凭据 + 选 Web-Enabled (+记住选择)
|
||
BL->>L: 写 simple.json (runMode, rememberRunMode)
|
||
end
|
||
L->>L: 切换 CycleGUI 到"服务状态窗"
|
||
L->>K: 启动 Kestrel :7001/7002 + WebTerminal :8223
|
||
L->>L: SchedulerRuntime.Start()
|
||
L->>P: spawn MiGu.Server.exe
|
||
P->>P: Kestrel :8080/8081 Up
|
||
P->>P: YARP 加载路由
|
||
P->>K: POST /api/internal/handshake (svcToken)
|
||
|
||
Note over U,RV: 管理员登录
|
||
U->>V: 访问 https://host:8080/admin
|
||
V->>P: POST /api/auth/login {scope=Platform}
|
||
P-->>V: { token, effectivePermissions }
|
||
V->>P: GET /api/sl/projection/map
|
||
P->>K: GET /api/projection/map (YARP 转发 + X-On-Behalf-Of)
|
||
K-->>P: 投影
|
||
P-->>V: 投影
|
||
V-->>V: Workspace3D iframe 加载 http://host:8223?scope=Platform&token=...
|
||
|
||
Note over U,RV: 运营人员登录
|
||
U->>RV: 访问 https://host:8080/monitor
|
||
RV->>P: POST /api/auth/login {scope=RCSMonitor}
|
||
P-->>RV: { token, effectivePermissions (受限) }
|
||
RV->>RV: 按 allowedOps/visibleWidgets 渲染
|
||
```
|
||
|
||
### 10.2 Desktop-Only 启动(对比)
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant U as 用户
|
||
participant L as Simple3
|
||
participant BL as BootLoginPanel
|
||
|
||
U->>L: 启动 Simple3.exe
|
||
L->>L: 读 simple.json (无记忆 或 选项=DesktopOnly)
|
||
L->>BL: 必要时弹出登录窗
|
||
U->>BL: 输入凭据 + 选 Desktop-Only
|
||
BL->>L: 验证通过
|
||
L->>L: 启动 CycleGUI 全功能 UI
|
||
L->>L: SchedulerRuntime.Start()
|
||
Note over L: 不启动 Kestrel<br/>不启动 WebTerminal<br/>不 spawn Platform
|
||
L-->>U: 进入设计端主界面
|
||
```
|
||
|
||
### 10.3 platform-vue 编辑地图站点 → Simple3 落库
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant V as platform-vue
|
||
participant P as MiGu.Server (YARP)
|
||
participant L as Simple3 (WebAPI)
|
||
participant DBl as simple_main.db
|
||
participant RV as rcsmonitor-vue (订阅)
|
||
|
||
V->>P: POST /api/sl/map/site {x, y, name}
|
||
P->>P: JWT + 鉴权 (map.site.write, scope=Platform)
|
||
P->>L: POST /api/map/site (YARP 转发 + X-On-Behalf-Of)
|
||
L->>L: 校验 + SimpleLib.SetSite()
|
||
L->>DBl: 写入 + DesignAuditLog
|
||
L-->>P: 201 Created { siteId }
|
||
P-->>V: 201 + siteId
|
||
L->>L: WS broadcast { type: "map.site.created", payload }
|
||
L-->>P: WS event
|
||
P-->>V: WS event (前端 Workspace3D iframe 收到 Simple3 推送的 PutModelObject 同步)
|
||
P-->>RV: WS event (RCSMonitor 接收并按权限展示)
|
||
```
|
||
|
||
### 10.4 平台编辑路径规划策略 → 主服务热加载
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant V as platform-vue
|
||
participant P as Platform
|
||
participant L as Simple3
|
||
participant E as DispatchLoop
|
||
participant RV as rcsmonitor-vue
|
||
|
||
V->>P: PUT /api/config/routing (payload, ifMatch=vPrev)
|
||
P->>P: 校验 schema + 权限 (config.routing.write)
|
||
P->>P: 写 platform.db (version+1, status=staged)
|
||
P->>L: PUT /api/sl/config/routing (YARP)
|
||
L->>L: ConfigSnapshot.AtomicSwap(vN)
|
||
L->>E: OnConfigChanged(routing)
|
||
E-->>L: ack
|
||
L-->>P: 200 OK { version: vN }
|
||
P->>P: status=active
|
||
P-->>V: 200 OK + 当前版本
|
||
P-->>RV: WS broadcast { type: "config.updated", section: "routing", version: vN }
|
||
```
|
||
|
||
### 10.5 rcsmonitor-vue 发「取消任务」运维命令
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant U as 运营人员
|
||
participant RV as rcsmonitor-vue
|
||
participant P as MiGu.Server (YARP)
|
||
participant L as Simple3 (Ops 网关)
|
||
participant E as DispatchLoop
|
||
participant DBp as platform.db
|
||
participant DBl as simple_main.db
|
||
|
||
U->>RV: 选中 Demand → 点击「取消」
|
||
RV->>RV: 客户端权限校验 (ops.task.cancel ∈ allowedOps?)
|
||
RV->>U: 二次确认
|
||
U->>RV: 确认
|
||
RV->>P: POST /api/sl/ops/task/cancel<br/>{demandId, idempotencyKey, reason}
|
||
P->>P: JWT + scope=RCSMonitor + 路径前缀 /api/sl/ops/* 命中白名单
|
||
P->>L: POST /api/ops/task/cancel (YARP + X-On-Behalf-Of + svcToken)
|
||
L->>L: 服务端鉴权 (ops.task.cancel) + 白名单 + 限流 + 幂等
|
||
L->>E: Pool.CancelDemand(id)
|
||
E-->>L: result
|
||
L->>DBl: 写 OpsAuditLog
|
||
L-->>P: 200 OK { status, auditId }
|
||
P->>DBp: 写 OpsLogs(source=RCSMonitor, auditId)
|
||
P-->>RV: 200 OK
|
||
RV-->>U: 提示成功
|
||
```
|
||
|
||
### 10.6 ROSE 主备切换序列
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant CLI as 客户端 (Vue/车端)
|
||
participant VIP as 浮动 IP
|
||
participant NA as NODE-A (Active)
|
||
participant ROSE as ROSE HA Engine
|
||
participant NB as NODE-B (Standby)
|
||
|
||
CLI->>VIP: REST / WS 请求
|
||
VIP->>NA: 路由到 Active
|
||
Note over NA: 节点故障
|
||
ROSE->>NA: 心跳超时 → 触发切换
|
||
ROSE->>NA: 强制停止 Simple3 / Platform
|
||
ROSE->>NA: 卸载 R: 卷
|
||
ROSE->>NB: 挂载 R: 卷
|
||
ROSE->>NB: 启动 Simple3 (WAL 重放 + 主库自检)
|
||
ROSE->>NB: 启动 MiGu.Server
|
||
ROSE->>VIP: 浮动 IP 漂移到 NODE-B
|
||
CLI--xVIP: 短暂中断
|
||
CLI->>VIP: 重连 (WS auto-reconnect)
|
||
VIP->>NB: 路由到 NODE-B (新 Active)
|
||
NB-->>CLI: 恢复服务
|
||
Note over CLI,NB: RTO 目标 < 60s,RPO ≈ 0
|
||
```
|
||
|
||
---
|
||
|
||
## 11. 通信协议矩阵
|
||
|
||
| 通道 | 协议 | 编码 | 端点 | 用途 |
|
||
|------|------|------|------|------|
|
||
| MiGu.Server (YARP) ↔ Simple3 | REST / WebSocket | JSON | `:7001` / `:7002` | 全功能 API 反代 + 事件订阅 |
|
||
| platform-vue ↔ MiGu.Server | REST / WebSocket | JSON | `:8080` / `:8081` (路径前缀 `/admin`) | UI 操作、事件推送 |
|
||
| rcsmonitor-vue ↔ MiGu.Server | REST / WebSocket | JSON | `:8080` / `:8081` (路径前缀 `/monitor`,`scope=RCSMonitor`) | UI 操作、事件推送(受限) |
|
||
| Vue Workspace3D ↔ Simple3 WebTerminal | WSS(webVRender 协议) | webVRender 自有 | `:8223` | 3D 视口同步(嵌入 iframe) |
|
||
| 子进程心跳 | Named Pipe | JSON | `\\.\pipe\simple-bootstrap` | 守护 / 重启 |
|
||
| Vehicle ↔ Simple3 | TCP / WS / OPC-UA | 业务私有 | `:8222` | 车端协议 |
|
||
| ROSE 心跳 | 专用网卡 + 串口 | ROSE 私有 | — | 节点健康监测 |
|
||
| ROSE 镜像复制 | 专用网卡 | ROSE 私有 | — | 块级实时数据同步 |
|
||
|
||
**WebAPI 约定:**
|
||
|
||
- 资源路径:`/api/{domain}/{resource}`,例:`/api/ops/task/cancel`、`/api/projection/map`、`/api/config/routing`;Platform 反代前缀 `/api/sl/*`
|
||
- 鉴权:`Authorization: Bearer <JWT>`;服务间互调附 `X-Svc-Token` + `X-On-Behalf-Of: <userId>` + `X-Scope: <scope>`
|
||
- 幂等:写操作支持 `Idempotency-Key` 请求头
|
||
- 版本化:配置类资源使用 `ETag` / `If-Match` 做乐观锁
|
||
- Swagger:Platform / Simple3 都暴露 `/swagger`(生产可关)
|
||
- **YARP Scope 白名单**:`scope=RCSMonitor` 时仅允许 `/api/sl/ops/*` 与 `/api/sl/projection/*` 命中;其他路径直接 403
|
||
|
||
---
|
||
|
||
## 12. 部署拓扑
|
||
|
||
```mermaid
|
||
flowchart TB
|
||
subgraph Cluster["双机 ROSE HA 集群 (Web-Enabled)"]
|
||
subgraph NA["NODE-A (Active)"]
|
||
SL_A["Simple3.exe<br/>Kestrel :7001/7002<br/>WebTerminal :8223"]
|
||
PL_A["MiGu.Server.exe<br/>:8080/8081<br/>(YARP + 双 Vue dist)"]
|
||
R_A["ROSE 受保护盘 R:\<br/>两库 (WAL)"]
|
||
end
|
||
subgraph NB["NODE-B (Standby)"]
|
||
SL_B["Simple3.exe (suspended)"]
|
||
PL_B["MiGu.Server.exe (suspended)"]
|
||
R_B["ROSE 镜像盘 R:\<br/>(实时同步)"]
|
||
end
|
||
NA <-- "ROSE 块级镜像 + 心跳" --> NB
|
||
VIP(("浮动 IP / VIP"))
|
||
VIP --> NA
|
||
end
|
||
|
||
subgraph Clients["客户端"]
|
||
Op["管理员浏览器<br/>https://vip:8080/admin"]
|
||
Run["运营浏览器<br/>https://vip:8080/monitor"]
|
||
Veh["AGV 车端"]
|
||
end
|
||
|
||
subgraph Cold["冷备 / 归档"]
|
||
NAS["NAS / 对象存储<br/>(夜间快照 + WAL 归档)"]
|
||
end
|
||
|
||
Op -- "HTTPS :8080" --> VIP
|
||
Run -- "HTTPS :8080" --> VIP
|
||
Veh -- "TCP :8222" --> VIP
|
||
|
||
NA -. "夜间 sqlite_backup + WAL 归档" .-> NAS
|
||
```
|
||
|
||
**端口规划(单逻辑节点):**
|
||
|
||
| 端口 | 服务 | 启用条件 |
|
||
|------|------|----------|
|
||
| 7001 | Simple3 WebAPI | Web-Enabled |
|
||
| 7002 | Simple3 WebSocket | Web-Enabled |
|
||
| 8080 | Platform WebAPI + platform-vue 静态(/admin)+ rcsmonitor-vue 静态(/monitor) | Web-Enabled |
|
||
| 8081 | Platform WebSocket | Web-Enabled |
|
||
| 8222 | Simple3 车端 / API(现有) | 所有模式 |
|
||
| 8223 | Simple3 WebTerminal(webVRender,Vue 嵌入用) | Web-Enabled |
|
||
|
||
> Desktop-Only 模式下:7001 / 7002 / 8080 / 8081 / 8223 全部**不监听**。
|
||
|
||
---
|
||
|
||
## 13. 仓库与解决方案规划
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
subgraph repo["Simple-FR 仓库"]
|
||
sln["Simple.sln"]
|
||
|
||
subgraph kernel["内核 (现有)"]
|
||
SC["SimpleCore"]
|
||
SS["SimpleScheduler"]
|
||
HC["HttpClientHelper"]
|
||
end
|
||
subgraph shared["共享 (新增)"]
|
||
SHC["SimpleShared.Contracts"]
|
||
SHA["SimpleShared.Auth"]
|
||
SHF["SimpleShared.Config"]
|
||
SHP["SimpleShared.Persistence"]
|
||
SHO["SimpleShared.OpsCommand"]
|
||
SHH["SimpleShared.WebApiHost"]
|
||
end
|
||
subgraph apps["两端后端"]
|
||
SL["Simple3 (CycleGUI + WebAPI)"]
|
||
PSrv["MiGu.Server (WebAPI + YARP)"]
|
||
end
|
||
subgraph frontends["前端 (pnpm workspace)"]
|
||
ShComp["packages/sl-controls<br/>(共享 Vue 组件库, 含 Workspace3D)"]
|
||
PVue["platform-vue (Vue 3 + Vite)"]
|
||
RVue["rcsmonitor-vue (Vue 3 + Vite)"]
|
||
end
|
||
subgraph plugins["插件"]
|
||
PG["Plugins / Sample / 第三方"]
|
||
end
|
||
subgraph ops["运维脚本"]
|
||
HA["tools/ha/<br/>(ROSE 资源脚本 + 切换演练)"]
|
||
end
|
||
end
|
||
|
||
SL --> SC
|
||
SL --> SS
|
||
SL --> HC
|
||
SL --> SHC
|
||
SL --> SHA
|
||
SL --> SHF
|
||
SL --> SHP
|
||
SL --> SHO
|
||
SL --> SHH
|
||
|
||
PSrv --> SC
|
||
PSrv --> SHC
|
||
PSrv --> SHA
|
||
PSrv --> SHF
|
||
PSrv --> SHP
|
||
PSrv --> SHO
|
||
PSrv --> SHH
|
||
|
||
PG -. 反射加载 .-> SL
|
||
ShComp --> PVue
|
||
ShComp --> RVue
|
||
PVue -- vite build --> PSrv
|
||
RVue -- vite build --> PSrv
|
||
```
|
||
|
||
### 13.1 pnpm workspace 配置示例
|
||
|
||
`frontends/pnpm-workspace.yaml`:
|
||
|
||
```yaml
|
||
packages:
|
||
- packages/*
|
||
- apps/*
|
||
```
|
||
|
||
`frontends/` 目录结构:
|
||
|
||
```text
|
||
frontends/
|
||
├── pnpm-workspace.yaml
|
||
├── package.json
|
||
├── packages/
|
||
│ └── sl-controls/ # 共享组件库(Workspace3D / MapEditor / CarPanel / MissionEditor / CadToolbar / OpsActionPanel / FieldsLayers ...)
|
||
│ ├── package.json
|
||
│ ├── src/
|
||
│ │ ├── Workspace3D.vue # 嵌入 webVRender iframe
|
||
│ │ ├── MapEditor.vue
|
||
│ │ ├── ...
|
||
│ │ └── index.ts
|
||
│ └── tsconfig.json
|
||
└── apps/
|
||
├── platform-vue/ # 管理员前端
|
||
│ ├── package.json # depends on "@simple/sl-controls"
|
||
│ └── src/
|
||
└── rcsmonitor-vue/ # 运营前端
|
||
├── package.json # depends on "@simple/sl-controls"
|
||
└── src/
|
||
```
|
||
|
||
`packages/sl-controls/package.json`(节选):
|
||
|
||
```json
|
||
{
|
||
"name": "@simple/sl-controls",
|
||
"version": "0.1.0",
|
||
"main": "src/index.ts",
|
||
"peerDependencies": {
|
||
"vue": "^3.4.0"
|
||
}
|
||
}
|
||
```
|
||
|
||
`apps/platform-vue/package.json`(节选):
|
||
|
||
```json
|
||
{
|
||
"dependencies": {
|
||
"@simple/sl-controls": "workspace:*",
|
||
"vue": "^3.4.0",
|
||
"pinia": "^2.1.0",
|
||
"vue-router": "^4.2.0",
|
||
"element-plus": "^2.5.0",
|
||
"echarts": "^5.5.0"
|
||
}
|
||
}
|
||
```
|
||
|
||
构建 + 部署:
|
||
|
||
```bash
|
||
cd frontends
|
||
pnpm install
|
||
pnpm --filter platform-vue build # 产出 apps/platform-vue/dist
|
||
pnpm --filter rcsmonitor-vue build # 产出 apps/rcsmonitor-vue/dist
|
||
# MiGu.Server 的发布脚本将这两个 dist 复制到 MiGu.Server/wwwroot/{admin,monitor}
|
||
```
|
||
|
||
---
|
||
|
||
## 14. 落地路线图
|
||
|
||
| 里程碑 | 周期估计 | 交付内容 |
|
||
|--------|----------|----------|
|
||
| **M0 - 内核下沉** | 1 周 | 新建 SimpleShared.* 6 个工程;Configuration → IConfigSnapshotProvider;EF Core + SQLite + 迁移 |
|
||
| **M1 - 启动登录 + 运行模式** | 1 周 | `BootLoginPanel`;`RunMode` 枚举;CycleGUI 状态窗;`simple.json.runMode` 持久化;Web-Enabled 业务面板硬隐藏 |
|
||
| **M2 - WebAPI 协议层** | 1.5 周 | Simple3 集成 Kestrel;定义 `/api/projection/*`、`/api/ops/*`、`/api/config/*`、`/api/map/*` 等;WS Hub;JWT |
|
||
| **M3 - 共享前端组件库** | 1.5 周 | `frontends/packages/sl-controls`:Workspace3D(嵌入 webVRender)+ 地图列表 + 任务表 + CAD 工具栏 + OpsActionPanel 等 |
|
||
| **M4 - Platform 后端 + YARP** | 2 周 | MiGu.Server(WebAPI + Swagger + YARP `/api/sl/*` + Scope 中间件 + 静态托管双 Vue dist)+ 配置中心 11 个 schema + 用户/角色/控件权限 |
|
||
| **M5 - platform-vue (管理员)** | 2.5 周 | 全功能套壳:登录、地图设计、车辆/任务、CAD、字段/图层、配置中心、库位、自定义控件、回放、设备管理、车队生命周期、场景模板 |
|
||
| **M6 - rcsmonitor-vue (运营)** | 1.5 周 | 按权限渲染;嵌入 webVRender(read-only);运维白名单动作面板;标注 |
|
||
| **M7 - Bootstrapper** | 1 周 | SystemMission 启动 Platform + 心跳 + Watchdog |
|
||
| **M8 - 高可用方案落地** | 2 周 | 默认路径 SQLite + ROSE(数据盘 / 启停脚本 / VIP / 切换演练,RTO < 60s 验收);另出 MySQL InnoDB Cluster / PostgreSQL Patroni / SQL Server Always On AG 三份部署指南与 CI 流水线 |
|
||
| **M9 - 自定义控件 + 控件级权限** | 2 周 | 控件 schema → platform-vue + rcsmonitor-vue 双渲染器;按 `WidgetGrant` 三档可见性裁剪 |
|
||
|
||
---
|
||
|
||
## 15. 已确认决策
|
||
|
||
| # | 议题 | 决策 |
|
||
|---|------|------|
|
||
| 1 | 运行模式持久化 | **写入 `simple.json.runMode` / `rememberRunMode`**(不使用 %APPDATA%) |
|
||
| 2 | Web-Enabled 下是否允许同时本地操作 | **不允许**;CycleGUI 仅状态窗;不提供"临时启用本地 UI"开关 |
|
||
| 3 | 3D 引擎 | **复用 Simple3 WebTerminal 的 webVRender**,Vue 通过 iframe / Web Component 嵌入 |
|
||
| 4 | 反向代理 | **YARP**(MiGu.Server 用 YARP 反代 `/api/sl/*`) |
|
||
| 5 | RCSMonitor 是否需要独立后端 | **否**,完全依赖 MiGu.Server;通过 `scope=RCSMonitor` + 角色 + WidgetGrant 限权 |
|
||
| 6 | 共享前端组件库 | **pnpm workspace + `frontends/packages/sl-controls`** |
|
||
| 7 | 运营白名单 | 采纳 §5.1 列表(10 条,后续可扩) |
|
||
| 8 | ROSE 复制粒度 | 块级镜像盘(RPO≈0)首选;视现场版本兜底文件级 |
|
||
| 9 | 车端连接策略 | 走 VIP,统一切换;车端实现 WS 自动重连 |
|
||
| 10 | **Platform / RCSMonitor 启动归属(v1.4)** | **由 Simple3 内置 `SystemMission.StartPlatformMission` 拉起并守护**;不允许独立安装 MiGu.Server.exe 为 Windows Service;MiGu.Server 启动时校验父进程必须是 Simple3 |
|
||
| 11 | **持久层多 Provider(v1.5)** | EF Core 抽象,**默认 SQLite + ROSE HA**;可选 **MySQL InnoDB Cluster / PostgreSQL Patroni / SQL Server Always On AG**;每 Provider 一套 EF Migrations,CI 全矩阵跑通;运行期由 `simple.json.database.provider` 决定 |
|
||
| 12 | **跨 Provider 切换策略** | 不支持热切;切换走停服窗口 + `tools/db/migrate.ps1`;旧文件作为回退包保留 |
|
||
|
||
---
|
||
|
||
## 16. 现有代码影响面
|
||
|
||
| 现有文件 | 改动方向 |
|
||
|----------|----------|
|
||
| `Simple3/Program.cs` | 在 `Enssentials.Load` 之后插入 `BootLoginPanel.RunModal()`;根据返回的 `RunMode` 决定后续路径 |
|
||
| `Simple3/Configuration.cs` | 拆为 `LocalBootConfig`(启动期,含 `runMode`、`rememberRunMode`、监听地址、各端口)+ `IConfigSnapshotProvider`(运行期);数据库路径走 `%SIMPLE_DATA_ROOT%` |
|
||
| `Simple3/Startup.cs` | 按 `RunMode` 分支:Desktop-Only 走原有 CycleGUI;Web-Enabled 启动 Kestrel + WebAPI + WebTerminal + Spawn Platform + 切换 CycleGUI 到状态窗 |
|
||
| `Simple3/UI/SimpleUI.cs` | 增加 `RunMode.WebEnabled` 时**所有业务面板硬性不创建**;新增"服务状态窗"面板(唯一允许) |
|
||
| `Simple3/UI/BootLoginPanel.cs`(新增) | 启动登录窗实现 + 模式持久化 |
|
||
| `Simple3/UI/ServiceStatusPanel.cs`(新增) | Web-Enabled 状态窗实现 |
|
||
| `Simple3/RCS/Mission.cs` | 抽出 `SystemMission` 抽象基类(与业务 Mission 同一基类但走独立 Registry,**不进入 DispatchLoop**) |
|
||
| `Simple3/RCS/SystemMissions/StartPlatformMission.cs`(新增) | 拉起 `MiGu.Server.exe`、绑定命名管道、上报心跳与状态到 ServiceStatusPanel |
|
||
| `Simple3/Bootstrap/ProcessHost.cs`(新增) | 封装 `System.Diagnostics.Process` + 日志重定向 + 优雅停止 |
|
||
| `Simple3/Bootstrap/HeartbeatChannel.cs`(新增) | 命名管道服务端 + JSON 心跳协议 |
|
||
| `Simple3/Bootstrap/SystemMissionRegistry.cs`(新增) | 注册/批量 Spawn/Stop SystemMission |
|
||
| `Simple3/Bootstrap/ProcessWatchdog.cs`(新增) | 指数退避重启 + 多次失败后熔断并通知状态窗 |
|
||
| `Simple3/Bootstrap/RunMode.cs`(新增) | `DesktopOnly` / `WebEnabled` 枚举 + 启动期校验 |
|
||
| `Simple3/Rendering/SimpleSceneRenderer.cs` | 按 webVRender 的 `?scope=` / `?ro=` 参数禁用编辑工具 |
|
||
| `SimpleScheduler/WebApi.cs` | 调用方从 Nancy 切到 ASP.NET Core Controller;保持 `SchedulerRuntime` 外观稳定 |
|
||
| `Simple3/SimpleProject.cs` | 持久化双写:JSON(兼容)+ SQLite(新主存,受 ROSE 保护盘) |
|
||
| `Plugins/Sample` | 示例插件读取 `IConfigSnapshotProvider`;不再读 `Configuration.conf` |
|
||
| 新增 `tools/ha/*` | ROSE 资源启停脚本、健康检查脚本、切换演练脚本 |
|
||
| 新增 `tools/db/*` | 跨 Provider 迁移脚本(`migrate.ps1` / `dump.ps1` / `restore.ps1`);按目标 DB 校验 schema 与索引 |
|
||
| 新增 `SimpleShared.Persistence/Providers/*` | 四个 Provider 适配(`SqliteProviderAdapter` / `MySqlProviderAdapter` / `NpgsqlProviderAdapter` / `SqlServerProviderAdapter`)+ `IDbProviderSpecifics` |
|
||
| 新增 `SimpleShared.Persistence/Migrations/{Sqlite,MySql,Npgsql,SqlServer}/*` | 四套 EF Core 迁移文件,CI 矩阵跑全 |
|
||
| 新增 `frontends/pnpm-workspace.yaml` | pnpm workspace 根 |
|
||
| 新增 `frontends/packages/sl-controls/` | 共享 Vue 组件库(含 Workspace3D 嵌 webVRender) |
|
||
| 新增 `frontends/apps/platform-vue/` | Vue 3 + Vite 工程,管理员全功能套壳 |
|
||
| 新增 `frontends/apps/rcsmonitor-vue/` | Vue 3 + Vite 工程,运营按权限渲染 |
|
||
| 新增 `MiGu.Server` 工程 | ASP.NET Core 8 WebAPI + YARP + 静态托管双 Vue dist |
|
||
|
||
---
|
||
|
||
## 17. 视觉规范(v1.6 新增,v1.6.1 对齐 FRLD)
|
||
|
||
### 17.1 品牌
|
||
|
||
| 项 | 取值 | 出现位置 |
|
||
|----|------|----------|
|
||
| 产品名 | **迷毂** | 登录窗标题 / `<title>` / 浏览器 favicon / 顶栏侧栏 logo / 文档抬头 |
|
||
| 全称 | **迷毂 · 智能调度平台** | 登录窗 H1、侧边栏中文标题 |
|
||
| 英文 | **Mi Gu · Intelligent Dispatch Platform** | 登录窗副标题、侧边栏英文副标 |
|
||
| 母公司 | **法睿兰达 FAIRYLAND**(FRLD) | 登录卡 / 侧边栏 顶部 logo |
|
||
| 工程标识(保持不动) | `MiGu.Server` / `simple-platform-vue` | csproj 名 / pnpm 包名 / 仓库目录;保持稳定避免破坏构建脚本 |
|
||
| Logo 资源 | `public/FRLD-logo-white.png` (11.5 KB) 展开态 + `public/FRLD-logo-white-no_title.png` (3.5 KB) 折叠态 | 侧边栏 / 登录卡;来源 `E:\ddms\frontend\public`(与 FAME 共用) |
|
||
| Favicon | `public/favicon.svg`(紫色渐变方块 + 白色「迷」字) | 浏览器标签页 |
|
||
| 登录背景 | `public/login-bg.jpg`(1.8 MB,原始素材 `C:\Tool\wallpapper\wall_Beach.jpg`) | 海滩 + 紫色叠加层 |
|
||
|
||
### 17.2 主色卡(v1.7 默认 · 工业紫色)
|
||
|
||
**默认主题 `industrial-purple`(工业紫)** — 登录后内容区与 AppShell 的基准色:
|
||
|
||
```
|
||
主色 PRIMARY #5a1890 rgb(90, 24, 144)
|
||
悬停 HOVER #7b1fa2 rgb(123, 31, 162)
|
||
按下 ACTIVE #38006b
|
||
强调 ACCENT #8e6abf rgb(142, 106, 191)
|
||
|
||
应用渐变起/中/止 #0c021c → #16082e → #04000e(内容卡片 92%+ 不透明,避免发灰)
|
||
侧栏渐变 rgba(--mg-bg-aside-rgb) → rgba(--mg-bg-app-deep-rgb)
|
||
```
|
||
|
||
> **历史**:v1.6.2 固定 `#641393`;v1.6.1 曾对齐 ddms 的 `#7c3aed`。v1.7 起以 `themes.ts` 为唯一色板源,`theme.css` 仅提供默认值与玻璃令牌。
|
||
>
|
||
> 实现位置:
|
||
> - `frontends/apps/simple-platform-vue/src/styles/themes.ts` — 6 套预设 + `applyThemeVars()`
|
||
> - `frontends/apps/simple-platform-vue/src/styles/theme.css` — `--mg-*` + Element Plus 覆盖
|
||
> - `frontends/apps/simple-platform-vue/src/stores/ui.ts` — `themeId` 持久化
|
||
|
||
### 17.3 状态色
|
||
|
||
为保持紫色品牌统一,状态色降饱和并往紫色侧偏移:
|
||
|
||
| 状态 | 取值 | RGB |
|
||
|------|------|-----|
|
||
| 成功 | `#6f8f4c` | 111, 143, 76 |
|
||
| 警告 | `#c98a1d` | 201, 138, 29 |
|
||
| 危险 | `#b3324f` | 179, 50, 79 |
|
||
| 信息 | `#7a6b87` | 122, 107, 135 |
|
||
|
||
### 17.4 登录窗视觉构成(§3.2 的物化形态,v1.6.1 对齐 ddms)
|
||
|
||
1. **背景层 (`z-index:0`)**:`url('/login-bg.jpg') center/cover`,filter `saturate(0.45) brightness(0.42)`,transform `scale(1.05)`。
|
||
2. **紫色叠加层 (`z-index:1`)**:径向渐变(左上 `rgba(168,85,247,0.55)` + 右下 `rgba(26,16,64,0.78)`)+ 主对角线深紫线性渐变。
|
||
3. **辉光球 (`z-index:1`)**:两个 blur(85px) 圆斑(左上 440px violet-300、右下 560px purple-500),各自 drift 18s 错相位呼吸。
|
||
4. **登录卡 (`z-index:2`)**:460px 宽,圆角 16px,背景 `linear-gradient(135deg, #2d1b69 0%, #7c3aed 100%)`,`box-shadow: 0 30px 80px rgba(10,10,40,0.55)` + 内边高光。
|
||
5. **品牌区**:52px FRLD logo(drop-shadow violet glow)+ H1 `迷 毂 · 智能调度平台`(letter-spacing 3px)+ 副标 `Mi Gu · Intelligent Dispatch Platform`(首字母 bolded)+ hint `请登录您的账号 · Web-Enabled`。
|
||
6. **表单**:透明 el-input(白字 + 半透明白边 + focus 紫色辉光)+ scope 双卡(选中态白底紫字)+ checkbox(白勾紫底)+ 高级折叠(端口配置 2x2 grid)+ 白底紫字 46px 大圆角主按钮(hover 上浮 2px)。
|
||
|
||
### 17.5 AppShell 视觉构成(v1.6.1 对齐 ddms)
|
||
|
||
1. **侧边栏**:自顶向下渐变 `#2d1b69 → #1a1040`,宽度 232px(折叠 64px),右侧细边 + `box-shadow: 2px 0 16px rgba(26,16,64,0.25)`。
|
||
2. **侧边栏顶端 Logo 块**:22/14 内边距,38px FRLD logo(drop-shadow `rgba(168,85,247,0.4)`),下方中文标题 `迷 毂 · 智能调度平台`(letter-spacing 2.5px)+ 英文副标 `Mi Gu · Intelligent Dispatch Platform`(首字母 bolded)。
|
||
3. **折叠态**:仅显示 28px FRLD 小 logo + 「迷毂」缩写。
|
||
4. **菜单态**:item margin 2/8 + 44px 高 + 圆角 8px;hover `rgba(168,85,247,0.18)`;active `linear-gradient(90deg, rgba(168,85,247,0.38), rgba(124,58,237,0.22))` + `inset 3px 0 0 #a855f7`。
|
||
5. **顶栏**:白底 + `box-shadow: 0 1px 6px rgba(45,27,105,0.06)`;面包屑 `#2d1b69`、分隔符 `#c4b5fd`。
|
||
6. **用户头像**:`linear-gradient(135deg, #a855f7, #7c3aed)` 圆形。
|
||
7. **页脚**:`color: var(--mg-primary-700)`、`border-top: 1px solid #f0ebf8`。
|
||
|
||
### 17.6 复用清单
|
||
|
||
要在新页面/组件中沿用品牌主色,优先使用 CSS 变量:
|
||
|
||
| 变量 | 用途 |
|
||
|------|------|
|
||
| `--mg-primary` | 任意主色字段(按钮、链接、强调) |
|
||
| `--mg-primary-{50..900}` | 主色阶梯,用于底色/边框/浅文字 |
|
||
| `--mg-bg-app` / `--mg-bg-aside` / `--mg-bg-aside-2` | 全局/侧边栏底色 |
|
||
| `--mg-text-light` / `--mg-text-muted` | 暗背景文本 |
|
||
| `--mg-divider` | 暗背景分割线 |
|
||
| Element Plus 自带 `var(--el-color-primary*)` | 已自动跟随主色 |
|
||
|
||
新写视图时请避免硬编码 `#641393` / `#7c3aed`(统一走 `var(--mg-primary)`、`rgba(var(--mg-*-rgb), α)`,以便主题切换生效)。
|
||
|
||
### 17.7 多主题色板切换(v1.7 新增)
|
||
|
||
| 文件 | 职责 |
|
||
|------|------|
|
||
| `src/styles/themes.ts` | `ThemePreset[]`:id / name / description / preview / `vars`(`--mg-*` 键值对) |
|
||
| `src/styles/theme.css` | 静态默认 + 玻璃令牌 + `.mg-content` 内 Element Plus 暗色适配 |
|
||
| `src/stores/ui.ts` | `themeId`、`setThemeId()`、`applyCurrentTheme()`、`localStorage` 键 `simple.ui.state` |
|
||
| `src/components/ThemeSwitcher.vue` | 顶栏下拉:色块预览 + 名称/描述 + 当前勾选 |
|
||
| `src/layouts/AppShell.vue` | 头部接入 `ThemeSwitcher`;壳层样式使用 `var(--mg-*)` |
|
||
| `src/main.ts` | `createPinia()` 后立即 `useUiStore(pinia).applyCurrentTheme()` |
|
||
|
||
**6 套预设 ID:**
|
||
|
||
| id | 名称 | 主色 preview |
|
||
|----|------|----------------|
|
||
| `industrial-purple` | 工业紫色(**默认**) | `#5a1890` |
|
||
| `deep-azure` | 深邃蓝 | `#1565c0` |
|
||
| `emerald-forge` | 翡翠绿 | `#00796b` |
|
||
| `crimson-iron` | 熔铁赤 | `#b71c1c` |
|
||
| `graphite-steel` | 石墨钢 | `#455a64` |
|
||
| `amber-forge` | 琥珀金 | `#e65100` |
|
||
|
||
**切换流程:** 用户选主题 → `setThemeId` → `applyThemeVars` 写 `:root` + `data-theme` 属性 → `persist()`。刷新页面后 `main.ts` 恢复。
|
||
|
||
**构建验证:** `pnpm --filter simple-platform-vue exec vue-tsc --noEmit` + `pnpm --filter simple-platform-vue build`(2026-05-20 已通过)。
|
||
|
||
---
|
||
|
||
## 18. 实现进度与待办(对照代码库)
|
||
|
||
> 工作目录:`E:\Work\Core\Simple-FR\Simple`。下列状态以仓库内**实际文件**为准,与 §14 里程碑对照;完成项在后续 PR/会话中应同步更新本表。
|
||
|
||
### 18.1 前端 `simple-platform-vue`(合并 admin + monitor)
|
||
|
||
| # | 项 | 文档依据 | 状态 | 代码位置 / 备注 |
|
||
|---|-----|----------|------|-----------------|
|
||
| F1 | pnpm workspace + 单 SPA | §13、frontends/README | ✅ 完成 | `frontends/apps/simple-platform-vue`;路由 `/admin/*` `/monitor/*` |
|
||
| F2 | 登录窗 §3.2 | §3.2、§17.4 | ✅ 完成 | `LoginView.vue`:双栏 hero、海滩背景、Mock 鉴权 |
|
||
| F3 | AppShell 玻璃风 | §17.5、v1.6.2 | ✅ 完成 | `AppShell.vue`:侧栏 FRLD logo、菜单、fade-up |
|
||
| F4 | Workspace3D / webVRender | §1、§11 | ✅ 完成 | `Workspace3D.vue` → `:8223` iframe |
|
||
| F5 | 配置中心 14 页骨架 | §9 | ✅ 完成 | `views/admin/config/*` + `ConfigPageBase` |
|
||
| F6 | 运营 monitor 视图 | §5、M6 | ✅ 骨架 | `views/monitor/*`(与 admin 同工程) |
|
||
| F7 | **多主题色板** | §17.7(v1.7) | ✅ 完成 | `themes.ts`、`ThemeSwitcher.vue`、`ui.ts`、`main.ts` |
|
||
| F8 | AppShell 壳层随主题变色 | §17.7 | ✅ 完成 | `AppShell.vue` 已改 `var(--mg-*)` |
|
||
| F9 | 登录页随主题变色 | §17.7 | ✅ 完成 | `BlankLayout` / `LoginView` 光球、叠加层、hero、按钮已改 `var(--mg-*)`;登录页内切换器仍 ☐(登录后顶栏可切) |
|
||
| F10 | `DashboardView` 图表色板 | §17.6 | ☐ 待办 | `MG_PALETTE` 仍为固定紫色数组,应读 `activeTheme` |
|
||
| F11 | 独立 `platform-vue` / `rcsmonitor-vue` | §13 | ☐ 未拆 | 当前有意合并;拆分时更新构建脚本 |
|
||
| F12 | `packages/sl-controls` | §13、M3 | ☐ 未建 | 组件仍在 app 内 `components/` |
|
||
| F13 | dist → `MiGu.Server/wwwroot` | §13 构建说明 | 🔄 需手动 | build 后复制 `dist/*`;`Program.cs` 已 `MapFallbackToFile` |
|
||
|
||
### 18.2 后端 `MiGu.Server`(骨架)
|
||
|
||
| # | 项 | 状态 | 备注 |
|
||
|---|-----|------|------|
|
||
| B1 | Kestrel + Swagger + CORS | ✅ | `Program.cs` |
|
||
| B2 | Auth / Health / Config / Ops / Projection 控制器 | ✅ 骨架 | Mock/内存存储 |
|
||
| B3 | YARP `/api/sl/*` → :8222 | ✅ 配置 | 依赖 Simple3 实际监听 |
|
||
| B4 | 静态托管 + SPA fallback | ✅ | 单一 `wwwroot/index.html` |
|
||
| B5 | JWT 真签发 + 库持久化 | ☐ | 仍为 Mock |
|
||
| B6 | 父进程 Simple3 校验 | ☐ | §4、§15 #10 |
|
||
|
||
### 18.3 Simple3 / 共享内核(ARCHITECTURE 主体)
|
||
|
||
| # | 项 | 状态 | 备注 |
|
||
|---|-----|------|------|
|
||
| S1 | `SimpleShared.*` 六工程 | ☐ 未建 | §6、M0 |
|
||
| S2 | `BootLoginPanel` + `RunMode` | ☐ | M1 |
|
||
| S3 | `SystemMission.StartPlatformMission` | ☐ | M7 |
|
||
| S4 | WebAPI Kestrel + WS | ☐ | M2 |
|
||
| S5 | 多 DB Provider + HA | ☐ | M0/M8 |
|
||
|
||
### 18.4 主题功能子任务(v1.7 专项)
|
||
|
||
| # | 子任务 | 状态 |
|
||
|---|--------|------|
|
||
| T1 | `themes.ts` 六套预设,工业紫默认 | ✅ |
|
||
| T2 | `theme.css` 全站 `--mg-*` + `.mg-content` EP 覆盖 | ✅ |
|
||
| T3 | `ui.ts`:`themeId` + `applyCurrentTheme` + localStorage | ✅ |
|
||
| T4 | `ThemeSwitcher.vue` 下拉组件 | ✅ |
|
||
| T5 | `AppShell` 顶栏接入 | ✅ |
|
||
| T6 | `main.ts` 启动恢复主题 | ✅ |
|
||
| T7 | `vue-tsc` + `vite build` | ✅ 2026-05-20 |
|
||
| T8 | 登录页变量化 + 可选登录页 ThemeSwitcher | 🔄 T8a 变量化 ✅;T8b 登录页 ThemeSwitcher ☐ |
|
||
| T9 | `ARCHITECTURE.md` / `frontends/README.md` 同步 | ✅ 本节 |
|
||
|
||
---
|
||
|
||
## 关联文档
|
||
|
||
- [SIMPLELITE_DEVELOPMENT_PLAN.md](./SIMPLELITE_DEVELOPMENT_PLAN.md) — Simple3 功能对齐执行计划
|
||
- [SIMPLELITE_COMPOSER_PARITY_PLAN.md](./SIMPLELITE_COMPOSER_PARITY_PLAN.md) — 与 SimpleComposer 差距分析
|