将 StandardScene 各插件的配置/监控窗体从 WinForms 迁移到 CycleGUI(删除 .Designer.cs/.resx,重写为 PanelBuilder 立即模式 UI,新增 CycleUiHelper 统一对话框)。 同时修复代码审核中的问题: - 后台文件写入加锁 + try/catch(ButtonBoxManager / DoorManager,对齐 LoopViewer.SaveTasks 模式) - CoderFieldsMetadata.cs 启用 #nullable enable,消除 CS8632 警告 - DummyCar 移除已废弃的 rightClickAction()/SetPosition() - CarRemoteHelper.OpenVehicleWebPage 的 Process.Start 加 try/catch - 重命名名不副实的 Mstsc()(现为打开网页) - 统一弃元命名为 _ - TrafficInterlockViewer 改用稳定 Id(GUID)做选择/编辑,替代行索引 - csproj 改用 $(CGUILibDir) 解析 CycleGUI,绝对路径收敛到 Directory.Build.props 构建:dotnet build StandardScene.sln → 0 错误,30 警告(均为历史遗留)。 注:static 单例状态重构(审核第 8 项)暂未处理,留待单独任务。
881 lines
26 KiB
HTML
881 lines
26 KiB
HTML
<!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>
|
||
</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 应用)运行,能力覆盖搬运调度、环线任务、
|
||
交通互锁、区域流量控制、充电协同、门控联动,以及 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>
|
||
<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>
|
||
</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>
|
||
|
||
<h4>构建步骤</h4>
|
||
<ol>
|
||
<li>先构建宿主依赖:<code>dotnet build Simple\SimpleLite\SimpleLite.csproj</code>(一并构建 SimpleCore)</li>
|
||
<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>
|
||
</ol>
|
||
|
||
<div class="warning">
|
||
当前项目已是 SDK 风格工程(`net8.0-windows`),目录下 `.cs` 文件会被自动包含,无需手工加入 `.csproj`。注意:StandardScene 通过 `HintPath` 引用宿主产物,构建前必须先编译 Simple 解决方案,否则会报 `SimpleCore` 版本不匹配。
|
||
</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;
|
||
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>
|
||
<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> |