Files
Migu2.0/MiGu.Server/Configs/DeploymentCatalog.cs
T

97 lines
5.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
namespace MiGu.Server.Configs;
/// <summary>
/// 配置向导「可选项目录」与「选型 → 平台能力」映射的单一事实来源。
///
/// <para>前端向导从 <c>GET /api/wizard/options</c> 拿到这些可选项渲染勾选框;后端
/// <see cref="ModuleToPages"/> 在「按选型裁剪菜单」时把模块
/// 映射为 PageCatalog 的可见页 id。集中定义,避免前后端各写一份导致漂移。</para>
/// </summary>
public static class DeploymentCatalog
{
/// <summary>一个可勾选项。<see cref="Id"/> 是稳定机器标识,<see cref="Group"/> 用于前端分组展示。</summary>
public record Option(string Id, string Name, string Group, string Description);
/// <summary>导航方式(多选,一等维度)。id 与 <see cref="DeploymentProfile.NavKindToSceneId"/> 的 key 对齐。</summary>
public static readonly IReadOnlyList<Option> NavigationKinds = new[]
{
new Option("magnetic", "磁导航", "navigation", "磁条循迹 + 地标 / RFID 定位"),
new Option("qrcode", "二维码导航", "navigation", "二维码地标 + 码值地图"),
new Option("laser", "激光导航", "navigation", "反光板 / SLAM + 激光避障"),
};
/// <summary>功能模块(多选)。暂定保留 WMS / PTL 两项,后续按需扩展(参考 RIOT 的 WMS/WCS/MES/APS 分层)。</summary>
public static readonly IReadOnlyList<Option> Modules = new[]
{
new Option("wms", "WMS 仓储管理", "module", "库位 / 库存 / 出入库管理"),
new Option("ptl", "PTL 拣选系统", "module", "Pick-to-Light 亮灯拣选与播种"),
};
/// <summary>
/// 功能模块 → PageCatalog 页面 Key 列表的映射。PTL 暂无专属配置页,未纳入映射(选中不影响菜单)。
/// 注意:Key 必须是 PageCatalog 当前有效 Key(不能用 LegacyKeyAliases 里的旧名,否则裁剪悄然失效)。
/// </summary>
public static readonly IReadOnlyDictionary<string, string[]> ModuleToPages =
new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase)
{
["wms"] = new[] { "admin-config-facility", "admin-config-warehouse" },
};
/// <summary>
/// 场景插件 → 平台页面 Key。磁导航选型会并入 <see cref="DeploymentProfile.SignalSceneId"/>
/// 从而点亮「数据中心」菜单(PLC 握手 + 磁条交管配置)。
/// </summary>
public static readonly IReadOnlyDictionary<string, string[]> SceneToPages =
new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase)
{
[DeploymentProfile.SignalSceneId] = new[] { "admin-data-center" },
};
/// <summary>所有「可被选型控制」的页面 Key(Module / Scene 映射值的并集)。</summary>
public static IReadOnlyCollection<string> TailorablePages()
{
var set = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (var v in ModuleToPages.Values) foreach (var p in v) set.Add(p);
foreach (var v in SceneToPages.Values) foreach (var p in v) set.Add(p);
return set;
}
/// <summary>当前部署画像下被「点亮」的可裁剪页(已启用 Module / 激活场景映射到的页)。</summary>
public static IReadOnlyCollection<string> EnabledPages(DeploymentProfile dp)
{
var set = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
if (dp == null) return set;
foreach (var m in dp.Modules ?? new List<string>())
if (ModuleToPages.TryGetValue(m, out var ps)) foreach (var p in ps) set.Add(p);
var activeScenes = dp.ToLauncherSceneIds();
foreach (var (sceneId, pages) in SceneToPages)
{
if (!activeScenes.Contains(sceneId, StringComparer.OrdinalIgnoreCase)) continue;
foreach (var p in pages) set.Add(p);
}
return set;
}
/// <summary>当前部署画像下应隐藏的页(可裁剪但未被点亮)。向导未完成(Configured=false)则不隐藏任何页。</summary>
public static IReadOnlyCollection<string> HiddenPages(DeploymentProfile dp)
{
if (dp == null || !dp.Configured) return Array.Empty<string>();
var enabled = EnabledPages(dp);
return TailorablePages().Where(p => !enabled.Contains(p)).ToList();
}
/// <summary>
/// 从 RBAC 计算出的可见页集合中移除「被部署画像隐藏」的页 —— 这是「按选型裁剪菜单」的核心。
/// 不在任何映射中的页不受影响;向导未完成时原样返回(避免首登空菜单)。
/// </summary>
public static List<string> FilterPagesByDeployment(IEnumerable<string> pages, DeploymentProfile dp)
{
var input = (pages ?? Enumerable.Empty<string>()).ToList();
if (dp == null || !dp.Configured) return input;
var hidden = new HashSet<string>(HiddenPages(dp), StringComparer.OrdinalIgnoreCase);
return input.Where(p => !hidden.Contains(p)).ToList();
}
}