Files

881 lines
26 KiB
HTML
Raw Permalink Normal View History

2026-06-14 11:19:15 +08:00
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>StandardScene 文档中心</title>
<style>
:root {
--bg: #09070f;
--bg-soft: #14101f;
--panel: rgba(27, 20, 43, 0.94);
--panel-2: rgba(19, 15, 31, 0.92);
--line: rgba(182, 148, 255, 0.2);
--line-strong: rgba(199, 170, 255, 0.42);
--text: #f4efff;
--text-soft: #c7c0db;
--muted: #9086aa;
--purple: #a855f7;
--purple-2: #7e22ce;
--purple-3: #e4cfff;
--magenta: #ff68c4;
--warn: #ffd56f;
--shadow: 0 18px 60px rgba(0, 0, 0, 0.45);
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html {
scroll-behavior: smooth;
}
body {
background:
radial-gradient(circle at top right, rgba(168, 85, 247, 0.18), transparent 26%),
radial-gradient(circle at left center, rgba(126, 34, 206, 0.12), transparent 26%),
linear-gradient(180deg, #06050a 0%, #0b0913 50%, #09070f 100%);
color: var(--text);
font-family: "Segoe UI", "Microsoft YaHei UI", "PingFang SC", "Segoe UI Emoji", "Apple Color Emoji", sans-serif;
line-height: 1.65;
}
body::before {
content: "";
position: fixed;
inset: 0;
pointer-events: none;
background:
linear-gradient(rgba(255, 255, 255, 0.02) 1px, transparent 1px),
linear-gradient(90deg, rgba(255, 255, 255, 0.02) 1px, transparent 1px);
background-size: 28px 28px;
mask-image: linear-gradient(180deg, rgba(0, 0, 0, 0.85), transparent 100%);
}
.shell {
width: min(1360px, calc(100% - 40px));
margin: 24px auto 56px;
}
.topbar {
position: sticky;
top: 0;
z-index: 10;
margin-bottom: 18px;
border: 1px solid var(--line);
border-radius: 18px;
background: rgba(9, 7, 15, 0.85);
backdrop-filter: blur(14px);
box-shadow: var(--shadow);
}
.topbar-inner {
display: flex;
align-items: center;
justify-content: space-between;
gap: 20px;
padding: 16px 22px;
}
.brand {
display: flex;
align-items: center;
gap: 14px;
}
.brand-mark {
width: 42px;
height: 42px;
display: grid;
place-items: center;
border: 1px solid var(--line-strong);
border-radius: 12px;
background: linear-gradient(135deg, rgba(168, 85, 247, 0.24), rgba(255, 104, 196, 0.14));
color: var(--purple-3);
font-weight: 700;
}
.brand h1 {
font-size: 1.08rem;
letter-spacing: 0.06em;
text-transform: uppercase;
}
.brand p {
color: var(--muted);
font-size: 0.9rem;
}
.nav {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.nav a,
.button {
color: var(--text-soft);
text-decoration: none;
padding: 10px 14px;
border: 1px solid var(--line);
border-radius: 999px;
background: rgba(255, 255, 255, 0.02);
transition: 0.2s ease;
}
.nav a:hover,
.button:hover {
color: var(--text);
border-color: var(--line-strong);
background: rgba(168, 85, 247, 0.1);
}
.hero {
position: relative;
overflow: hidden;
border: 1px solid var(--line);
border-radius: 28px;
background: linear-gradient(135deg, rgba(26, 19, 43, 0.95), rgba(13, 10, 21, 0.95));
box-shadow: var(--shadow);
padding: 38px;
margin-bottom: 22px;
}
.hero::after {
content: "";
position: absolute;
inset: auto -80px -80px auto;
width: 300px;
height: 300px;
border-radius: 50%;
background: radial-gradient(circle, rgba(168, 85, 247, 0.24), transparent 68%);
pointer-events: none;
}
.eyebrow {
display: inline-flex;
align-items: center;
gap: 10px;
margin-bottom: 18px;
padding: 8px 12px;
border-radius: 999px;
border: 1px solid var(--line);
color: var(--purple-3);
background: rgba(168, 85, 247, 0.08);
font-size: 0.92rem;
}
.hero h2 {
font-size: clamp(2.2rem, 5vw, 4.4rem);
line-height: 1.06;
margin-bottom: 14px;
}
.hero p {
max-width: 840px;
color: var(--text-soft);
font-size: 1.05rem;
margin-bottom: 20px;
}
.stats {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 14px;
margin: 22px 0 28px;
}
.stat {
padding: 18px;
border: 1px solid var(--line);
border-radius: 18px;
background: rgba(255, 255, 255, 0.03);
}
.stat .value {
font-size: 1.35rem;
font-weight: 700;
color: var(--purple-3);
}
.stat .label {
color: var(--muted);
font-size: 0.9rem;
margin-top: 6px;
}
.hero-actions {
display: flex;
flex-wrap: wrap;
gap: 12px;
}
.button.primary {
color: #fff;
border-color: rgba(216, 180, 254, 0.36);
background: linear-gradient(135deg, #7e22ce, #a855f7);
box-shadow: 0 10px 28px rgba(126, 34, 206, 0.3);
}
.layout {
display: grid;
grid-template-columns: 300px minmax(0, 1fr);
gap: 18px;
align-items: start;
}
aside,
section.panel {
border: 1px solid var(--line);
border-radius: 24px;
background: var(--panel);
box-shadow: var(--shadow);
}
aside {
position: sticky;
top: 92px;
padding: 22px;
}
.side-title {
font-size: 0.9rem;
color: var(--purple-3);
letter-spacing: 0.08em;
text-transform: uppercase;
margin-bottom: 14px;
}
.toc {
display: grid;
gap: 10px;
margin-bottom: 22px;
}
.toc a {
text-decoration: none;
color: var(--text-soft);
padding: 10px 12px;
border-radius: 14px;
border: 1px solid transparent;
background: rgba(255, 255, 255, 0.02);
transition: 0.2s ease;
}
.toc a:hover {
color: var(--text);
border-color: var(--line);
background: rgba(168, 85, 247, 0.08);
}
.quick-note {
padding: 16px;
border: 1px solid var(--line);
border-radius: 18px;
background: var(--panel-2);
color: var(--text-soft);
font-size: 0.92rem;
}
.content {
display: grid;
gap: 18px;
}
.panel {
padding: 28px;
}
.panel h3 {
font-size: 1.55rem;
margin-bottom: 16px;
color: var(--purple-3);
}
.panel h4 {
font-size: 1.08rem;
margin: 22px 0 10px;
color: #f8f4ff;
}
.panel p,
.panel li {
color: var(--text-soft);
}
.panel ul,
.panel ol {
padding-left: 20px;
display: grid;
gap: 8px;
}
.cards {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 14px;
margin-top: 12px;
}
.card {
padding: 18px;
border: 1px solid var(--line);
border-radius: 18px;
background: linear-gradient(180deg, rgba(255, 255, 255, 0.03), rgba(255, 255, 255, 0.01));
}
.card strong {
display: block;
margin-bottom: 6px;
color: var(--text);
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 12px;
border: 1px solid var(--line);
border-radius: 16px;
overflow: hidden;
}
th,
td {
text-align: left;
padding: 14px 16px;
border-bottom: 1px solid var(--line);
vertical-align: top;
}
th {
color: var(--purple-3);
background: rgba(168, 85, 247, 0.08);
font-weight: 600;
}
tr:last-child td {
border-bottom: none;
}
code {
font-family: Consolas, "Cascadia Code", monospace;
}
pre {
margin-top: 12px;
padding: 18px;
overflow: auto;
border: 1px solid var(--line);
border-radius: 18px;
background: linear-gradient(180deg, rgba(11, 9, 19, 0.98), rgba(19, 15, 31, 0.98));
color: #efe5ff;
}
.pill-row {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 16px;
}
.pill {
padding: 8px 12px;
border-radius: 999px;
border: 1px solid var(--line);
background: rgba(255, 255, 255, 0.03);
color: var(--text-soft);
font-size: 0.92rem;
}
.warning {
margin-top: 16px;
padding: 16px 18px;
border-left: 3px solid var(--warn);
border-radius: 14px;
background: rgba(255, 213, 111, 0.08);
color: #ffefc1;
}
.footer {
margin-top: 18px;
padding: 20px 24px;
border: 1px solid var(--line);
border-radius: 20px;
background: rgba(15, 11, 24, 0.92);
color: var(--muted);
text-align: center;
}
@media (max-width: 1080px) {
.layout {
grid-template-columns: 1fr;
}
aside {
position: static;
}
.cards,
.stats {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (max-width: 720px) {
.shell {
width: min(100% - 20px, 100%);
margin: 10px auto 28px;
}
.topbar-inner {
flex-direction: column;
align-items: flex-start;
}
.hero,
.panel,
aside {
padding: 20px;
}
.cards,
.stats {
grid-template-columns: 1fr;
}
}
</style>
</head>
<body>
<div class="shell">
<header class="topbar">
<div class="topbar-inner">
<div class="brand">
<div class="brand-mark">SS</div>
<div>
<h1>StandardScene Documentation Hub</h1>
<p>本地可直接打开 · UTF-8 · 中文 / English / emoji ✅</p>
</div>
</div>
<nav class="nav">
<a href="#overview">总览</a>
<a href="#architecture">架构</a>
<a href="#quickstart">快速开始</a>
<a href="#configs">配置</a>
<a href="#troubleshooting">排错</a>
</nav>
</div>
</header>
<section class="hero">
<div class="eyebrow">工业紫文档门户 · Offline Ready · No Deploy Needed</div>
<h2>StandardScene 开发指南与快速开始</h2>
<p>
本页面已经把开发指南、模块地图、构建方式、快速开始案例和常见排错整合到一个 HTML 文件中。
你可以直接双击 `DocumentHub.html` 打开,无需部署、无需联网、无需额外资源。
</p>
<div class="stats">
<div class="stat">
<div class="value">.NET 8</div>
<div class="label">工程目标框架 (net8.0-windows)</div>
2026-06-14 11:19:15 +08:00
</div>
<div class="stat">
<div class="value">Plugin DLL</div>
<div class="label">输出为 `StandardScene.dll`</div>
</div>
<div class="stat">
<div class="value">Mission + CarType</div>
<div class="label">两类核心扩展入口</div>
</div>
<div class="stat">
<div class="value">中文 / EN / 😎</div>
<div class="label">字体与编码已兼容</div>
</div>
</div>
<div class="hero-actions">
<a class="button primary" href="#quickstart">查看快速开始</a>
<a class="button" href="DEVELOPMENT_GUIDE.md">打开 Markdown 开发指南</a>
<a class="button" href="QUICK_REFERENCE.md">打开速查手册</a>
</div>
</section>
<div class="layout">
<aside>
<div class="side-title">On This Page</div>
<div class="toc">
<a href="#overview">01. 项目总览</a>
<a href="#architecture">02. 运行架构</a>
<a href="#modules">03. 模块地图</a>
<a href="#buildrun">04. 构建与运行</a>
<a href="#quickstart">05. 快速开始案例</a>
<a href="#configs">06. 配置文件</a>
<a href="#api">07. API 入口</a>
<a href="#workflow">08. 开发工作流</a>
<a href="#troubleshooting">09. 常见排错</a>
</div>
<div class="quick-note">
推荐第一步:先做 `HelloMission`,再做 `Region1=1` 的区域流控实验。前者帮助理解插件生命周期,后者帮助理解字段驱动与事件订阅。
</div>
</aside>
<main class="content">
<section class="panel" id="overview">
<h3>01. 项目总览</h3>
<p>
`StandardScene` 是 AGV/AMR 场景插件库,不是独立 EXE。它依赖宿主 `SimpleLite.exe`CycleGUI 应用)运行,能力覆盖搬运调度、环线任务、
2026-06-14 11:19:15 +08:00
交通互锁、区域流量控制、充电协同、门控联动,以及 HTTP / MQTT / Modbus 等外围接口。
</p>
<div class="cards">
<div class="card">
<strong>项目定位</strong>
作为宿主插件被加载,核心职责是“场景逻辑”而不是“独立应用”。
</div>
<div class="card">
<strong>最小理解单元</strong>
`Mission` 负责场景流程,`CarType` 负责车型与协议。
</div>
<div class="card">
<strong>最先阅读文件</strong>
`Scheduler/HeartBeatMission.cs`、`Scheduler/RegionalTrafficControlMission.cs`
</div>
</div>
<div class="pill-row">
<span class="pill">输出类型:Library</span>
<span class="pill">宿主:SimpleLite.exe</span>
2026-06-14 11:19:15 +08:00
<span class="pill">外部接口:Nancy / HTTP</span>
<span class="pill">典型协议:MQTT / Modbus</span>
</div>
</section>
<section class="panel" id="architecture">
<h3>02. 运行架构</h3>
<table>
<thead>
<tr>
<th>层级</th>
<th>角色</th>
<th>典型文件</th>
</tr>
</thead>
<tbody>
<tr>
<td>宿主层</td>
<td>启动程序、装载插件、展示配置与 Mission</td>
<td><code>SimpleLite.exe</code></td>
2026-06-14 11:19:15 +08:00
</tr>
<tr>
<td>场景逻辑层</td>
<td>任务调度、区域流控、充电、门禁等</td>
<td><code>Scheduler/</code><code>Chained/</code><code>Charge/</code></td>
</tr>
<tr>
<td>车辆协议层</td>
<td>各车型接入与状态同步</td>
<td><code>CarTypes/</code></td>
</tr>
<tr>
<td>基础能力层</td>
<td>路径规划、锁点、全局对象访问</td>
<td><code>SimpleCore</code><code>SimpleLib</code></td>
</tr>
</tbody>
</table>
<h4>宿主装载流程</h4>
<ol>
<li>编译得到 <code>StandardScene.dll</code></li>
<li>构建事件将 DLL 复制到 <code>build/plugins</code></li>
<li>宿主启动后扫描插件目录</li>
<li>通过特性反射识别 <code>MissionType</code><code>CarType</code></li>
<li>用户或 API 启动对应场景逻辑</li>
</ol>
</section>
<section class="panel" id="modules">
<h3>03. 模块地图</h3>
<table>
<thead>
<tr>
<th>目录</th>
<th>职责</th>
<th>建议起步文件</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>Scheduler/</code></td>
<td>心跳、安全信号、区域流控等轻量 Mission</td>
<td><code>HeartBeatMission.cs</code></td>
</tr>
<tr>
<td><code>Chained/</code></td>
<td>搬运与环线任务主流程</td>
<td><code>TransportMission.cs</code></td>
</tr>
<tr>
<td><code>Charge/</code></td>
<td>充电站管理、策略控制、状态维护</td>
<td><code>StandardChargeMission.cs</code></td>
</tr>
<tr>
<td><code>InterLock/</code></td>
<td>区域互锁、交通控制</td>
<td><code>TrafficInterlockMission.cs</code></td>
</tr>
<tr>
<td><code>CarTypes/</code></td>
<td>车型与协议实现</td>
<td><code>VDA5050Car.cs</code></td>
</tr>
<tr>
<td><code>ExtendDevice/Door/</code></td>
<td>门禁联动</td>
<td><code>DoorMission.cs</code></td>
</tr>
<tr>
<td><code>WebApi.cs</code></td>
<td>外部系统接入入口</td>
<td><code>/car/*</code><code>/map/*</code><code>/mission_reflection/*</code></td>
</tr>
</tbody>
</table>
</section>
<section class="panel" id="buildrun">
<h3>04. 构建与运行</h3>
<h4>本机依赖路径</h4>
<pre><code>D:\MDCS\Dependencies\Commons\CommonUsage.dll
D:\MDCS\Dependencies\Commons\MDCSToolBox.dll
D:\MDCS\Dependencies\Commons\CycleGUI.dll
..\Simple\SimpleLite\bin\Debug\SimpleLite.dll
..\Simple\SimpleLite\bin\Debug\LessokajiWeaverUtilities.dll
..\Simple\SimpleCore\bin\Debug\netstandard2.0\SimpleCore.dll</code></pre>
2026-06-14 11:19:15 +08:00
<h4>构建步骤</h4>
<ol>
<li>先构建宿主依赖:<code>dotnet build Simple\SimpleLite\SimpleLite.csproj</code>(一并构建 SimpleCore</li>
2026-06-14 11:19:15 +08:00
<li>打开 <code>StandardScene.sln</code></li>
<li>编译 <code>Debug|x64</code><code>Release|x64</code></li>
<li>确认 <code>Directory.Build.targets</code> 已将 5 个插件 DLL 复制到 <code>build/plugins</code></li>
<li><code>build/plugins</code> 部署到宿主 <code>plugins/</code>,运行 <code>SimpleLite.exe</code></li>
2026-06-14 11:19:15 +08:00
</ol>
<div class="warning">
当前项目已是 SDK 风格工程(`net8.0-windows`),目录下 `.cs` 文件会被自动包含,无需手工加入 `.csproj`。注意:StandardScene 通过 `HintPath` 引用宿主产物,构建前必须先编译 Simple 解决方案,否则会报 `SimpleCore` 版本不匹配。
2026-06-14 11:19:15 +08:00
</div>
</section>
<section class="panel" id="quickstart">
<h3>05. 快速开始案例</h3>
<h4>案例 A:新增 HelloMission</h4>
<p>
这是推荐的新手第一练。它直接沿用 `Scheduler/HeartBeatMission.cs` 的结构,只保留最小生命周期:`Create()`、`Execute()`、`Stop()`。
</p>
<pre><code>using System.Threading;
using Newtonsoft.Json;
using SimpleLite.RCS;
2026-06-14 11:19:15 +08:00
using SimpleCore;
namespace StandardScene.Scheduler
{
[MissionType(Name = "Hello Mission", editor = typeof(HelloMission))]
[I18N.DocumentTranslation(Name = "Hello Mission", locale = "en")]
public class HelloMission : Mission
{
[JsonIgnore] private bool _started;
[JsonIgnore] private Thread _thread;
public static Mission Create()
{
return new HelloMission();
}
public override void Execute()
{
if (_started) return;
_started = true;
status.status = "已启动";
_thread = new Thread(() =>
{
int count = 0;
while (_started)
{
Thread.Sleep(1000);
count++;
status.status = $"tick:{count}";
}
});
_thread.Start();
}
public void Stop()
{
_started = false;
status.status = "已停止";
}
}
}</code></pre>
<ol>
<li>新建 <code>Scheduler/HelloMission.cs</code>SDK 工程自动包含)</li>
<li>补上 <code>[MissionType]</code> 特性与静态 <code>Create()</code></li>
<li>编译后部署到宿主 <code>plugins/</code>,运行 <code>SimpleLite.exe</code></li>
2026-06-14 11:19:15 +08:00
<li>启动后观察 <code>status.status</code> 是否按秒递增</li>
</ol>
<h4>案例 B:区域流控实验</h4>
<p>
该案例对应 <code>Scheduler/RegionalTrafficControlMission.cs</code>。给同一区域的站点加字段 <code>Region1=1</code>,即可限制该区域最多同时只有 1 台车。
</p>
<pre><code>Region1 = 1</code></pre>
<ol>
<li>给目标区域内多个站点都加上相同的 <code>Region1</code> 字段</li>
<li>启动“区域流量监控” Mission</li>
<li>让两台车依次申请进入该区域</li>
<li>观察第二台车是否被阻止,日志和状态里会记录拦截次数</li>
</ol>
</section>
<section class="panel" id="configs">
<h3>06. 配置文件</h3>
<table>
<thead>
<tr>
<th>文件</th>
<th>用途</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>Config/traffic.json</code></td>
<td>交通互锁与区域控制</td>
</tr>
<tr>
<td><code>Config/ChargeStations.json</code></td>
<td>充电桩定义</td>
</tr>
<tr>
<td><code>Config/ChargeStrategyConfig.json</code></td>
<td>充电策略</td>
</tr>
<tr>
<td><code>Config/AlarmConfigs.json</code></td>
<td>充电报警配置</td>
</tr>
<tr>
<td><code>DoorConfig.json</code></td>
<td>门禁设备配置</td>
</tr>
<tr>
<td><code>tasklist.json</code></td>
<td>环线任务列表</td>
</tr>
<tr>
<td><code>simple.json</code></td>
<td>宿主基础配置</td>
</tr>
</tbody>
</table>
<p>
除了 JSON 文件,很多逻辑还大量依赖站点、车辆和轨道的 <code>fields</code><code>tags</code>。例如区域流控依赖以
<code>Region</code> 开头的字段,许多调度逻辑依赖 <code>group</code><code>giveWay</code><code>standby</code> 等字段。
</p>
</section>
<section class="panel" id="api">
<h3>07. API 入口</h3>
<p><code>WebApi.cs</code> 是外部系统最重要的进入点,仓库中已可看到这些典型路由:</p>
<div class="cards">
<div class="card">
<strong><code>/car/createTask</code></strong>
创建任务
</div>
<div class="card">
<strong><code>/car/getAllCars</code></strong>
查询车辆列表
</div>
<div class="card">
<strong><code>/car/goSite</code></strong>
指派车辆去站点
</div>
<div class="card">
<strong><code>/map/getMap</code></strong>
获取地图
</div>
<div class="card">
<strong><code>/task/getTask</code></strong>
查询任务
</div>
<div class="card">
<strong><code>/mission_reflection/*</code></strong>
反射调用 Mission 方法
</div>
</div>
</section>
<section class="panel" id="workflow">
<h3>08. 开发工作流</h3>
<ol>
<li>先定位功能属于哪个目录</li>
<li>找最接近的现有类作为模板</li>
<li>明确它依赖 JSON 配置还是 `fields` / `tags`</li>
<li>补齐日志、状态和停止逻辑</li>
<li>确认新文件已加入工程</li>
<li>编译后在宿主中验证是否被识别</li>
</ol>
<div class="pill-row">
<span class="pill">新增 Mission:先看 HeartBeatMission</span>
<span class="pill">新增区域逻辑:先看 RegionalTrafficControlMission</span>
<span class="pill">新增接口:先看 WebApi.cs</span>
<span class="pill">新增配置:先写默认值与生效时机</span>
</div>
</section>
<section class="panel" id="troubleshooting">
<h3>09. 常见排错</h3>
<table>
<thead>
<tr>
<th>现象</th>
<th>优先检查</th>
</tr>
</thead>
<tbody>
<tr>
<td>新增 Mission 在宿主里看不到</td>
<td>特性是否正确、`Create()` 是否存在、文件是否已加入 `.csproj`、插件是否复制到 `build/plugins`</td>
</tr>
<tr>
<td>区域流控不生效</td>
<td>站点字段名是否以 `Region` 开头、字段值是否为整数、Mission 是否已启动</td>
</tr>
<tr>
<td>车不动或任务不走</td>
<td>车辆在线状态、路径是否可达、是否被锁点 / 互锁 / 门控拦截</td>
</tr>
<tr>
<td>API 调不通</td>
<td>路由是否正确、宿主端口是否打开、请求是否真的命中 `WebApi.cs`</td>
</tr>
</tbody>
</table>
<div class="warning">
编码说明:本页使用 `UTF-8` 和兼容中文 / English / emoji 的字体栈,本地双击打开不依赖任何外部资源,因此不会因为部署或 CDN 缺失导致乱码。
</div>
</section>
</main>
</div>
<footer class="footer">
StandardScene 文档门户 · 工业紫风格 · 可离线直接打开 · UTF-8 Safe
</footer>
</div>
</body>
</html>