从 Simple-FR 拆出 Platform.Server 并重命名为 MiGu.Server;frontends 源码与构建脚本迁入本仓库。地图监控在 projection/cars 失败或为空时回退 reflection 车辆列表;Simple 仓库已移除旧 Platform.Server。 Co-authored-by: Cursor <cursoragent@cursor.com>
92 KiB
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-*;uistore 的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-radius14/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不再被视为"独立的业务平台服务",而是 SimpleLite 内置SystemMission(StartPlatformMission)拉起、被 SimpleLite Bootstrapper 守护的受控子进程;RCSMonitor 不存在独立后端进程,复用 MiGu.Server。- 整体定位章节重写:明确"两类后端可执行文件 + 一个进程编排者"的关系,避免读者误以为 Platform 是用 Windows Service / systemd 独立部署的服务。
v1.3 变更(保留):
- 取消 RCSMonitor.Server:
rcsmonitor-vue不再有独立后端进程,直接连 MiGu.Server;由 JWT 中的scope=RCSMonitor+ 角色权限码 +WidgetGrant三层限制可见控件与可调用 API。- 3D 渲染基座定为 webVRender:复用 SimpleLite WebTerminal 已经提供的 webVRender,以 Web Component / iframe 嵌入到 platform-vue 与 rcsmonitor-vue,两端共享同一份 Workspace 协议(PutModel / PutPointCloud / SetCamera 等 DTO)。
- 反向代理选定 YARP:MiGu.Server 内置 YARP 做
/api/sl/*→ SimpleLite WebAPI 的反代;带鉴权与审计中间件。- 运行模式持久化到
simple.json:登录窗"记住模式"勾选后写入simple.json.runMode;下次启动直接进入。- Web-Enabled 下严禁同时本地操作:CycleGUI 主窗只剩"服务状态窗",所有业务面板硬性隐藏;不提供"临时启用本地 UI"开关。
- 共享前端组件库:使用 pnpm workspace +
frontends/packages/sl-controls,封装 Workspace3D / 地图 / 任务 / CAD 等可复用 Vue 组件。
目录
- 总体目标与拆分原则
- 顶层系统架构(C4 - 容器视图)
- 启动登录与运行模式
- 进程拓扑与生命周期
- 三端职责矩阵
- 共享内核分层
- 数据库与高可用(多 Provider)
- 用户 / 权限模型(含控件级权限)
- 平台配置中心
- 关键交互序列
- 通信协议矩阵
- 部署拓扑
- 仓库与解决方案规划
- 落地路线图
- 已确认决策
- 现有代码影响面
- 视觉规范(v1.6 新增)
- 实现进度与待办(对照代码库)
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 核心拆分原则
-
Crash-Isolation(搞不崩主服务)
Platform / RCSMonitor 对地图/任务/车辆等写操作都通过 SimpleLite 的/api/*网关;主服务侧做白名单 + 幂等校验 + 频次限流 + 审计。Platform-Vue 走完整 API 集,RCSMonitor-Vue 仅限运维白名单/api/ops/*。 -
共享数据模型,独立运行时
地图、车辆、任务三端共用SimpleCore的 DTO;调度引擎只在 SimpleLite 里跑,Platform 只持有"投影"。 -
库分离 + 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。
-
统一协议层
所有进程间调用统一 WebAPI(REST/JSON)+ WebSocket 事件流;Vue 端直接对接 Platform 后端的 REST + WS;Platform 后端用 YARP 反代 SimpleLite 的设计/调度 API。 -
统一身份
SimpleShared.Auth提供 JWT + RBAC;Platform 是主权限源(在线时),SimpleLite 在 Desktop-Only 下用本地用户表降级。 -
运行模式互斥(强约束)
- Desktop-Only:CycleGUI 客户端独占;WebAPI / Platform 不启动。
- Web-Enabled:WebAPI 启动;Platform 子进程启动;CycleGUI 客户端所有业务面板硬性隐藏,仅保留"服务状态窗";不允许"临时启用本地 UI"开关——任何本地操作必须重启进设计模式。
- 模式由启动登录界面选择并持久化到
simple.json.runMode;下次启动可勾选"记住选择"直接进入。
-
控件级权限
Platform / RCSMonitor 登录后向SimpleShared.Auth拉取EffectivePermissions { allowedOps[], visibleWidgets[] };Vue 渲染器按集合裁剪面板、按钮、菜单、右键项。
2. 顶层系统架构(C4 - 容器视图)
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 启动流程
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 增量字段
{
"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 面板)
┌──────────────────────────────────────────┐
│ 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 进程关系图
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 |
生命周期:
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(PlatformvsRCSMonitor)与对应角色绑定的权限码 / 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. 共享内核分层
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,最简单稳定):
<!-- 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 反向代理配置(示例)
// 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 路由:
{
"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 矩阵)
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 不同时,逻辑表名一致;物理实现差异(uuidvsbinary(16)、jsonvsnvarchar(max)、自增策略等)由迁移文件适配。
7.3 SQLite + ROSE HA(默认 / 边缘单机)
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
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 / 流复制
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
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(默认)
{
"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
{
"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
{
"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
{
"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 CoreIModel反序列化每张表后批量写入目标。 - 滚动升级:不支持热切;停服窗口内执行迁移;保留旧 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. 用户 / 权限模型(含控件级权限)
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
落地四件套:
- 认证:
SimpleShared.Auth提供JwtIssuer;Web-Enabled 时 MiGu.Server 签发;Desktop-Only 时 SimpleLite 本地签发短期 Token(24h)。 - 授权:所有 WebAPI + WS 调用走
IPermissionEvaluator;权限码<area>.<action>。 - 范围(Scope):
Lite/Platform/RCSMonitor/*;同一用户在不同端可用集合不同。Vue 端登录时由前端代码根据访问路径自动带入scope(/admin/*→Platform,/monitor/*→RCSMonitor)。 - 控件级权限:除
Permission外,角色还可关联WidgetGrant,每个WidgetId三档可见性:hidden:根本不渲染readonly:渲染但禁用交互interactive:完全可交互(仍受操作权限码二次校验)
8.1 RCSMonitor 登录与权限拉取
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 双渲染器) |
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# 示例)
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 三端建链
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 启动(对比)
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 落库
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 平台编辑路径规划策略 → 主服务热加载
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 发「取消任务」运维命令
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 主备切换序列
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. 部署拓扑
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. 仓库与解决方案规划
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:
packages:
- packages/*
- apps/*
frontends/ 目录结构:
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(节选):
{
"name": "@simple/sl-controls",
"version": "0.1.0",
"main": "src/index.ts",
"peerDependencies": {
"vue": "^3.4.0"
}
}
apps/platform-vue/package.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"
}
}
构建 + 部署:
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)
- 背景层 (
z-index:0):url('/login-bg.jpg') center/cover,filtersaturate(0.45) brightness(0.42),transformscale(1.05)。 - 紫色叠加层 (
z-index:1):径向渐变(左上rgba(168,85,247,0.55)+ 右下rgba(26,16,64,0.78))+ 主对角线深紫线性渐变。 - 辉光球 (
z-index:1):两个 blur(85px) 圆斑(左上 440px violet-300、右下 560px purple-500),各自 drift 18s 错相位呼吸。 - 登录卡 (
z-index:2):460px 宽,圆角 16px,背景linear-gradient(135deg, #2d1b69 0%, #7c3aed 100%),box-shadow: 0 30px 80px rgba(10,10,40,0.55)+ 内边高光。 - 品牌区:52px FRLD logo(drop-shadow violet glow)+ H1
迷 毂 · 智能调度平台(letter-spacing 3px)+ 副标Mi Gu · Intelligent Dispatch Platform(首字母 bolded)+ hint请登录您的账号 · Web-Enabled。 - 表单:透明 el-input(白字 + 半透明白边 + focus 紫色辉光)+ scope 双卡(选中态白底紫字)+ checkbox(白勾紫底)+ 高级折叠(端口配置 2x2 grid)+ 白底紫字 46px 大圆角主按钮(hover 上浮 2px)。
17.5 AppShell 视觉构成(v1.6.1 对齐 ddms)
- 侧边栏:自顶向下渐变
#2d1b69 → #1a1040,宽度 232px(折叠 64px),右侧细边 +box-shadow: 2px 0 16px rgba(26,16,64,0.25)。 - 侧边栏顶端 Logo 块:22/14 内边距,38px FRLD logo(drop-shadow
rgba(168,85,247,0.4)),下方中文标题迷 毂 · 智能调度平台(letter-spacing 2.5px)+ 英文副标Mi Gu · Intelligent Dispatch Platform(首字母 bolded)。 - 折叠态:仅显示 28px FRLD 小 logo + 「迷毂」缩写。
- 菜单态:item margin 2/8 + 44px 高 + 圆角 8px;hover
rgba(168,85,247,0.18);activelinear-gradient(90deg, rgba(168,85,247,0.38), rgba(124,58,237,0.22))+inset 3px 0 0 #a855f7。 - 顶栏:白底 +
box-shadow: 0 1px 6px rgba(45,27,105,0.06);面包屑#2d1b69、分隔符#c4b5fd。 - 用户头像:
linear-gradient(135deg, #a855f7, #7c3aed)圆形。 - 页脚:
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 功能对齐执行计划
- SIMPLELITE_COMPOSER_PARITY_PLAN.md — 与 SimpleComposer 差距分析