# SimpleLite 三端系统架构设计 > **Migu2.0 仓库说明**:平台后端已拆至本仓库,工程名为 **`MiGu.Server`**(原 `Platform.Server`)。SimpleLite 与前端源码仍在兄弟仓库 `Simple`。下文中的 `MiGu.Server` 即指本仓库 `MiGu.Server/` 目录。 > 文档版本:v1.7.0 > 更新日期:2026-05-20 > 范围:SimpleLite(主程序 / 设计端 / 调度引擎宿主 / 进程编排器)+ Platform(业务平台 · 同时承载管理员前端 platform-vue 与运营前端 rcsmonitor-vue · 共用一套 WebAPI · **主入口为 MiGu.Server,登录后拉起 SimpleLite**) > 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-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` 自动玻璃卡。 > - **路由切换微动效**:`` 包裹 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、``、用户可见文案、`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` 不再被视为"独立的业务平台服务",而是 SimpleLite 内置 `SystemMission`(`StartPlatformMission`)拉起、被 SimpleLite 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**:复用 SimpleLite 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/*` → SimpleLite 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 现场打造的「**设计 → 调度 → 运营监控**」三端协同系统。 **三个"端"对应三套用户体验,但只有两类后端可执行文件,且都由 SimpleLite 统一编排:** | 端 | 前端载体 | 后端可执行文件 | **启动者** | 角色 | 写权限 | |----|----------|----------------|------------|------|--------| | **SimpleLite 桌面端** | CycleGUI 客户端 | `SimpleLite.exe` 自身 | 用户双击 / 服务管理器 | 主程序 + 调度引擎宿主 + 全功能 WebAPI 提供者 + **进程编排器(Bootstrapper + SystemMission)** | **全功能** | | **Platform 管理端** | `platform-vue` (Vue 3 SPA) | `MiGu.Server.exe` | **SimpleLite 内置 `SystemMission.StartPlatformMission` 拉起**(Web-Enabled 时自动 spawn;崩溃由 SimpleLite Watchdog 重启) | **SimpleLite 全能力套壳**:管理员侧 Vue 前端复刻所有设计/调度控件 + 业务平台特有能力(配置中心 / 外部对接 / 库位 / 账号) | **全功能**(等价 SimpleLite) | | **RCSMonitor 运营端** | `rcsmonitor-vue` (Vue 3 SPA) | **共用 `MiGu.Server.exe`**(无独立后端进程) | 随 MiGu.Server 一起被 SimpleLite 拉起 | 运营监控前端:按 `scope=RCSMonitor` + 角色权限 + WidgetGrant 三层裁剪 UI;可对任务/车辆执行白名单运维动作 | **受限**(仅运维白名单) | **关键澄清(v1.4 重点):** - **后端可执行文件只有 2 个**:`SimpleLite.exe`、`MiGu.Server.exe`。 - **进程启动只有 1 个真正的入口**:用户/服务管理器只启动 `SimpleLite.exe`,MiGu.Server 由 SimpleLite 自己拉起,**不需要也不允许独立安装为 Windows Service**。 - **进程编排归属 SimpleLite**:`SystemMission` 是 SimpleLite 自带的 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 端无法访问。 > 一句话:**用户点 SimpleLite.exe,由 SimpleLite 通过 Mission 把 Platform 后端拉起来;Platform 后端再把两套 Vue 端服好。** ### 1.2 核心拆分原则 1. **Crash-Isolation(搞不崩主服务)** Platform / RCSMonitor 对**地图/任务/车辆等写操作**都通过 SimpleLite 的 `/api/*` 网关;主服务侧做白名单 + 幂等校验 + 频次限流 + 审计。Platform-Vue 走完整 API 集,RCSMonitor-Vue 仅限运维白名单 `/api/ops/*`。 2. **共享数据模型,独立运行时** 地图、车辆、任务三端共用 `SimpleCore` 的 DTO;调度引擎只在 SimpleLite 里跑,Platform 只持有"投影"。 3. **库分离 + Provider 抽象**(详见 §7) - `simple_main` 由 SimpleLite 持有;`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** 反代 SimpleLite 的设计/调度 API。 5. **统一身份** `SimpleShared.Auth` 提供 JWT + RBAC;Platform 是主权限源(在线时),SimpleLite 在 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["SimpleLite 主进程 (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/* → SimpleLite 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 ``` **要点:** - **只有两个后端可执行文件**:`SimpleLite.exe` 与 `MiGu.Server.exe`;RCSMonitor 不再有独立后端。 - **`MiGu.Server.exe` 由 SimpleLite 的 SystemMission 拉起**:用户只启动 SimpleLite;Web-Enabled 时 `StartPlatformMission` 自动 spawn MiGu.Server,子进程心跳异常由 Bootstrapper 重启。 - **`PL_Static` 同一进程双 SPA 托管**:浏览器访问路径决定加载哪份 dist,登录时也按路径决定 `scope` 参数。 - **`PL_YARP` 把 `/api/sl/*` 反代到 SimpleLite**:YARP 在请求转发前后挂中间件做 JWT 校验、权限码二次确认、写操作审计、`Idempotency-Key` 透传、Scope 检查(RCSMonitor 的请求仅允许命中 `/api/ops/*` 这一前缀)。 - **3D 由 SimpleLite 的 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([SimpleLite.exe 启动]) --> CheckPrev{simple.json 中<br/>runMode 已记忆?} CheckPrev -- 否 --> Login[弹出登录窗<br/>SimpleLite 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 | "SimpleLite · 启动登录" | | 用户名 | 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 | 不进入主程序,退出进程 | > 实现位置:新增 `SimpleLite/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 | **必须退出 SimpleLite 重新登录**;不支持热切(避免半启动状态) | | Web-Enabled 运行中 | CycleGUI 主窗只显示状态窗(运行时长 / 在线用户 / 端口 / 主备状态)+「停止」按钮 | | Web-Enabled 下用户尝试本地控件 | **所有业务面板硬性不渲染**;Workspace 视口也不显示;用户无法通过任何方式重新启用 | | Web-Enabled 异常退出 | Watchdog 重新拉起,恢复到 Web-Enabled;不强迫用户重选 | | 想取消"记住模式" | 启动时按住 `Shift` 或运行 `SimpleLite.exe --re-login` 强制弹出登录窗 | | 远程开关模式 | Platform 管理员可以发 `POST /api/sl/runmode/reset` 把 `rememberRunMode` 置为 `false`,**仅在下次重启时生效** | ### 3.4 服务状态窗(Web-Enabled 唯一可见的 CycleGUI 面板) ```text ┌──────────────────────────────────────────┐ │ SimpleLite 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["SimpleLite.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["SimpleLite 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 新增章节) SimpleLite 现有 `Mission` 是业务任务(运送/搬运),新增 **`SystemMission`** 作为同一基类的"系统级 Mission",用于拉起并守护进程级服务。它**不参与调度引擎的 DispatchLoop**,由 Bootstrapper 直接驱动。 **关键类:** | 类型 | 类型 / 命名空间 | 职责 | |------|------------------|------| | `SystemMission`(抽象) | `SimpleLite.RCS.SystemMissions` | 继承自现有 `Mission`,新增 `Spawn() / Stop() / Heartbeat()` 等抽象方法 | | `StartPlatformMission` | `SimpleLite.RCS.SystemMissions` | 拉起 `MiGu.Server.exe`;通过命名管道 `\\.\pipe\simple-bootstrap` 接收心跳 | | `SystemMissionRegistry` | `SimpleLite.Bootstrap` | 单例,注册所有 SystemMission;Web-Enabled 启动时遍历 `Spawn()`;进程退出时遍历 `Stop()` | | `ProcessHost` | `SimpleLite.Bootstrap` | 封装 `System.Diagnostics.Process` + 重定向标准输出到日志 + 退出码捕获 | | `HeartbeatChannel` | `SimpleLite.Bootstrap` | 命名管道服务端;JSON 协议 `{ "ts", "rss", "queueDepth", "status" }`;3 个周期未达 → 标记不健康 | | `ProcessWatchdog` | `SimpleLite.Bootstrap` | 不健康时 `Stop() + Spawn()`;指数退避 1s → 2s → 4s → 8s → 30s(上限) | | `RunMode`(枚举) | `SimpleLite.Bootstrap` | `DesktopOnly` / `WebEnabled` | **生命周期:** ```text SimpleLite 启动 (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",停止重试,需人工介入 SimpleLite 优雅停机: SystemMissionRegistry.StopAll() └─ StartPlatformMission.Stop() ├─ 发送 SIGTERM 等价(命名管道 "shutdown" 消息) ├─ 等待 MiGu.Server 完成 IHostedService.StopAsync (≤ 30s) └─ 超时则 ProcessHost.Kill() ``` **实现要点:** - **位置**:新建 `SimpleLite/Bootstrap/` 与 `SimpleLite/RCS/SystemMissions/`。 - **不写入主库 Missions 表**:SystemMission 是进程级配置,不参与项目序列化;存储在 `simple_main.db.SystemMissionConfig`(或直接读 `simple.json`)。 - **崩溃隔离**:Platform 异常不影响 SimpleLite 调度循环;MiGu.Server 也实现 `IHostedService.StopAsync` 做 WAL Checkpoint + WS 排空 → 给 ROSE 释放磁盘。 - **多实例预防**:通过命名互斥体 + `simple.json.allowMultiple=false`(已有)确保 SimpleLite 唯一;MiGu.Server 启动时校验"父进程是否为 SimpleLite",否则拒绝启动(防止有人手动双击 `MiGu.Server.exe`)。 - **静态资源**:MiGu.Server 用 `MapWhen + UseStaticFiles + UseSpa` 各挂一份 `index.html`。 --- ## 5. 三端职责矩阵 | 维度 | SimpleLite 桌面端 | **Platform 管理端(platform-vue)** | **RCSMonitor 运营端(rcsmonitor-vue)** | |------|---------------------|------------------------------------------|------------------------------------------| | 地图(站点/轨道/区域)编辑 | **读写**(Desktop-Only) | **全功能读写**(Vue 地图控件内嵌SimpleLite地图) | 只读投影,不可编辑 | | 任务编排(Mission/Recipe) | **读写** | **全功能读写**(含 Demand / Recipe) | 基础动作:暂停/取消/重派/优先级 | | 车辆配置(参数 / 维护策略) | **读写** | **全功能读写** | 基础动作:暂停/继续/结束任务/上线/离线/手动充电等 | | CAD 工具 | **可用** | **可用**(Vue 调用 `/api/sl/cad/*`) | 不可用 | | 自定义字段 / 图层 | **可用** | **可用** | 只读 | | 调度引擎(DispatchLoop) | 进程内拥有 | 远程订阅状态 + 全 API 操作 | 远程订阅状态 + 受限 API | | 车端通信 | 拥有 | 不直连,只看投影 | 不直连,只看投影 | | 3D 视口 | 本地 OpenGL(CycleGUI 原生) | **嵌入 SimpleLite webVRender**(全功能交互) | **嵌入 SimpleLite 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["SimpleLite (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 反代 SimpleLite** + 静态托管两份 Vue dist;**启动时校验父进程为 SimpleLite,否则拒绝运行**(防误用) | | `platform-vue` | Vue 3 + Vite + Pinia | 全功能套壳:复刻 SimpleLite 所有控件 | | `rcsmonitor-vue` | Vue 3 + Vite + Pinia | 运营监控:按权限渲染,运维动作面板 | | `packages/sl-controls`(pnpm workspace) | Vue 3 组件库 | Workspace3D(嵌 webVRender)/ 地图列表 / 任务表 / CAD 工具栏等共享组件 | ### 6.1 Platform Vue 控件复刻清单(与 SimpleLite CycleGUI 对照) | SimpleLite CycleGUI 面板 | Vue 组件(位于 `sl-controls`) | 备注 | |--------------------------|--------------------------------|------| | 主菜单栏 / 工具栏 | `<AppShell>` 顶栏 + 侧栏 | platform-vue 全功能;rcsmonitor-vue 仅显示运营菜单 | | Workspace 3D 视口 | `<Workspace3D>` | **iframe / Web Component 嵌入 SimpleLite 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> ``` `SimpleLite/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 给 SimpleLite 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["应用代码 (SimpleLite / 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** | SimpleLite | 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["SimpleLite.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["SimpleLite.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: SimpleLite (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["SimpleLite.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["SimpleLite.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["SimpleLite.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,SimpleLite 桌面端可走 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=SimpleLite" }, "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 时 SimpleLite 本地签发短期 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 SimpleLite (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["SimpleLite (主服务)"] 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}` 推到 SimpleLite,主服务原子切换 + ack;失败自动回滚,WS `config.rollback` 广播。 --- ## 10. 关键交互序列 ### 10.1 启动登录 + Web-Enabled 三端建链 ```mermaid sequenceDiagram participant U as 用户 participant L as SimpleLite (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: 启动 SimpleLite.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 SimpleLite participant BL as BootLoginPanel U->>L: 启动 SimpleLite.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 编辑地图站点 → SimpleLite 落库 ```mermaid sequenceDiagram participant V as platform-vue participant P as MiGu.Server (YARP) participant L as SimpleLite (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 收到 SimpleLite 推送的 PutModelObject 同步) P-->>RV: WS event (RCSMonitor 接收并按权限展示) ``` ### 10.4 平台编辑路径规划策略 → 主服务热加载 ```mermaid sequenceDiagram participant V as platform-vue participant P as Platform participant L as SimpleLite 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 SimpleLite (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: 强制停止 SimpleLite / Platform ROSE->>NA: 卸载 R: 卷 ROSE->>NB: 挂载 R: 卷 ROSE->>NB: 启动 SimpleLite (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) ↔ SimpleLite | 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 ↔ SimpleLite WebTerminal | WSS(webVRender 协议) | webVRender 自有 | `:8223` | 3D 视口同步(嵌入 iframe) | | 子进程心跳 | Named Pipe | JSON | `\\.\pipe\simple-bootstrap` | 守护 / 重启 | | Vehicle ↔ SimpleLite | 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 / SimpleLite 都暴露 `/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["SimpleLite.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["SimpleLite.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 | SimpleLite WebAPI | Web-Enabled | | 7002 | SimpleLite WebSocket | Web-Enabled | | 8080 | Platform WebAPI + platform-vue 静态(/admin)+ rcsmonitor-vue 静态(/monitor) | Web-Enabled | | 8081 | Platform WebSocket | Web-Enabled | | 8222 | SimpleLite 车端 / API(现有) | 所有模式 | | 8223 | SimpleLite 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["SimpleLite (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 周 | SimpleLite 集成 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 引擎 | **复用 SimpleLite 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)** | **由 SimpleLite 内置 `SystemMission.StartPlatformMission` 拉起并守护**;不允许独立安装 MiGu.Server.exe 为 Windows Service;MiGu.Server 启动时校验父进程必须是 SimpleLite | | 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. 现有代码影响面 | 现有文件 | 改动方向 | |----------|----------| | `SimpleLite/Program.cs` | 在 `Enssentials.Load` 之后插入 `BootLoginPanel.RunModal()`;根据返回的 `RunMode` 决定后续路径 | | `SimpleLite/Configuration.cs` | 拆为 `LocalBootConfig`(启动期,含 `runMode`、`rememberRunMode`、监听地址、各端口)+ `IConfigSnapshotProvider`(运行期);数据库路径走 `%SIMPLE_DATA_ROOT%` | | `SimpleLite/Startup.cs` | 按 `RunMode` 分支:Desktop-Only 走原有 CycleGUI;Web-Enabled 启动 Kestrel + WebAPI + WebTerminal + Spawn Platform + 切换 CycleGUI 到状态窗 | | `SimpleLite/UI/SimpleUI.cs` | 增加 `RunMode.WebEnabled` 时**所有业务面板硬性不创建**;新增"服务状态窗"面板(唯一允许) | | `SimpleLite/UI/BootLoginPanel.cs`(新增) | 启动登录窗实现 + 模式持久化 | | `SimpleLite/UI/ServiceStatusPanel.cs`(新增) | Web-Enabled 状态窗实现 | | `SimpleLite/RCS/Mission.cs` | 抽出 `SystemMission` 抽象基类(与业务 Mission 同一基类但走独立 Registry,**不进入 DispatchLoop**) | | `SimpleLite/RCS/SystemMissions/StartPlatformMission.cs`(新增) | 拉起 `MiGu.Server.exe`、绑定命名管道、上报心跳与状态到 ServiceStatusPanel | | `SimpleLite/Bootstrap/ProcessHost.cs`(新增) | 封装 `System.Diagnostics.Process` + 日志重定向 + 优雅停止 | | `SimpleLite/Bootstrap/HeartbeatChannel.cs`(新增) | 命名管道服务端 + JSON 心跳协议 | | `SimpleLite/Bootstrap/SystemMissionRegistry.cs`(新增) | 注册/批量 Spawn/Stop SystemMission | | `SimpleLite/Bootstrap/ProcessWatchdog.cs`(新增) | 指数退避重启 + 多次失败后熔断并通知状态窗 | | `SimpleLite/Bootstrap/RunMode.cs`(新增) | `DesktopOnly` / `WebEnabled` 枚举 + 启动期校验 | | `SimpleLite/Rendering/SimpleSceneRenderer.cs` | 按 webVRender 的 `?scope=` / `?ro=` 参数禁用编辑工具 | | `SimpleScheduler/WebApi.cs` | 调用方从 Nancy 切到 ASP.NET Core Controller;保持 `SchedulerRuntime` 外观稳定 | | `SimpleLite/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 | ✅ 配置 | 依赖 SimpleLite 实际监听 | | B4 | 静态托管 + SPA fallback | ✅ | 单一 `wwwroot/index.html` | | B5 | JWT 真签发 + 库持久化 | ☐ | 仍为 Mock | | B6 | 父进程 SimpleLite 校验 | ☐ | §4、§15 #10 | ### 18.3 SimpleLite / 共享内核(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) — SimpleLite 功能对齐执行计划 - [SIMPLELITE_COMPOSER_PARITY_PLAN.md](./SIMPLELITE_COMPOSER_PARITY_PLAN.md) — 与 SimpleComposer 差距分析