将调度内核标识从 SimpleLite 全面重命名为 Simple3。

配置段/环境变量、Launcher、健康检查 API、OpenAPI 与前后端文案同步;兼容探测旧 SimpleLite 进程名。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
黄兆尉
2026-08-26 17:46:52 +08:00
co-authored by Cursor
parent 912c44c9bb
commit 3686abdc78
79 changed files with 922 additions and 832 deletions
@@ -3,7 +3,7 @@ import http from './http'
/**
* AI 助手 API:会话/工具走 axios(带鉴权拦截器);对话走原生 fetch 流式(SSE),
* 因为 EventSource 只能 GET、且无法设置 Authorization header。fetch 这里手动对齐
* axios 的双轨鉴权(Cookie + Bearer + X-Scope)。后端见 SimpleLite `Web/Assistant/AssistantApi.cs`。
* axios 的双轨鉴权(Cookie + Bearer + X-Scope)。后端见 Simple3 `Web/Assistant/AssistantApi.cs`。
*/
const API_BASE = (import.meta.env.VITE_API_BASE as string | undefined) ?? '/api'
@@ -120,7 +120,7 @@ export async function streamChat(
if (!resp.ok || !resp.body) {
let msg = `请求失败(HTTP ${resp.status}`
if (resp.status === 403) msg = '无权使用 AI 助手(需要 Platform 权限)。'
else if (resp.status === 502 || resp.status === 504) msg = 'SimpleLite 未连接:请先启动后端(端口 8222)。'
else if (resp.status === 502 || resp.status === 504) msg = 'Simple3 未连接:请先启动后端(端口 8222)。'
else {
try {
const t = await resp.text()
@@ -32,7 +32,7 @@ export async function fetchFleetHealth(): Promise<FleetHealthRow[]> {
await new Promise((r) => setTimeout(r, 120))
return mockFleetHealth()
}
// 平台侧聚合:SimpleLite 指标 + WatchDog(:9776) TCP RTT。
// 平台侧聚合:Simple3 指标 + WatchDog(:9776) TCP RTT。
// 不再直打 /sl/projection/fleet/health(其探测车载 :8081,现场多数未开导致假超时 2000ms)。
try {
const { data } = await http.get<FleetHealthRow[]>('/fleet/health')
@@ -7,7 +7,7 @@ export interface HealthInfo {
uptimeSec: number
}
export interface SimpleLiteDiagnostics {
export interface Simple3Diagnostics {
enabled: boolean
isRunning: boolean
lastLaunchMode?: string | null
@@ -18,7 +18,7 @@ export interface SimpleLiteDiagnostics {
deployHint?: string | null
}
export interface SimpleLiteLaunchResult {
export interface Simple3LaunchResult {
started: boolean
status: string
detail: string
@@ -30,29 +30,26 @@ export function getHealth() {
return http.get<HealthInfo>('/health')
}
export function getSimpleLiteDiagnostics() {
return http.get<SimpleLiteDiagnostics>('/health/simplelite')
export function getSimple3Diagnostics() {
return http.get<Simple3Diagnostics>('/health/simple3')
}
export function stopSimpleLite() {
return http.post<{ killed: number; diagnostics: SimpleLiteDiagnostics }>('/health/simplelite/stop')
export function stopSimple3() {
return http.post<{ killed: number; diagnostics: Simple3Diagnostics }>('/health/simple3/stop')
}
export function restartSimpleLite(launchMode: LaunchMode) {
return http.post<{ restart: SimpleLiteLaunchResult; diagnostics: SimpleLiteDiagnostics }>(
'/health/simplelite/restart',
export function restartSimple3(launchMode: LaunchMode) {
return http.post<{ restart: Simple3LaunchResult; diagnostics: Simple3Diagnostics }>(
'/health/simple3/restart',
null,
{ params: { launchMode }, timeout: 60_000 }
)
}
/** 从诊断/会话 runMode 推断重启时使用的 launchMode。 */
/** Simple3 仅 Web;重启一律 WebOnly(保留函数签名供旧调用方)。 */
export function resolveRestartLaunchMode(
lastLaunchMode: string | null | undefined,
runMode: RunMode | null | undefined
_lastLaunchMode?: string | null,
_runMode?: RunMode | null
): LaunchMode {
const mode = (lastLaunchMode ?? '').toLowerCase()
if (mode === 'web') return 'WebOnly'
if (mode === 'web+local') return 'DesktopAndWeb'
return runMode === 'WebOnly' ? 'WebOnly' : 'DesktopAndWeb'
return 'WebOnly'
}
@@ -31,21 +31,21 @@ http.interceptors.request.use((config: InternalAxiosRequestConfig) => {
})
/**
* 把 axios 异常翻译成更友好的中文文案,特别是 SimpleLite 链路:
* 把 axios 异常翻译成更友好的中文文案,特别是 Simple3 链路:
*
* /api/sl/projection/** → Platform.Server YARP → SimpleLite EmbedIO :8222
* /api/sl/projection/** → Platform.Server YARP → Simple3 EmbedIO :8222
*
* 如果 SimpleLite 没启动 / 端口未监听,YARP 一定回 502;超时一般是 504。把这两种
* 情况单独识别,写成「SimpleLite 未连接,请先启动 SimpleLite (端口 8222)」之类,
* 如果 Simple3 没启动 / 端口未监听,YARP 一定回 502;超时一般是 504。把这两种
* 情况单独识别,写成「Simple3 未连接,请先启动 Simple3 (端口 8222)」之类,
* 比直接抛 `Request failed with status code 502` 友好得多,也避免用户怀疑前端 bug。
*/
function describeError(err: AxiosError): string {
const status = err.response?.status
const url = err.config?.url ?? ''
const isSimpleLite = url.startsWith('/sl/') || url.startsWith('sl/')
const isSimple3 = url.startsWith('/sl/') || url.startsWith('sl/')
if (status === 502 || status === 504 || err.code === 'ECONNABORTED' || err.code === 'ERR_NETWORK') {
if (isSimpleLite) {
return 'SimpleLite 未连接:请先启动 SimpleLite 后端(监听端口 8222)后重试。'
if (isSimple3) {
return 'Simple3 未连接:请先启动 Simple3 后端(监听端口 8222)后重试。'
}
return `网关无法连接到下游服务(${status ?? err.code ?? 'network'})。`
}
@@ -2,8 +2,8 @@ import type { AxiosError } from 'axios'
import http from './http'
/**
* 与 SimpleLite `MapEditApiController` 对应的前端胶水。
* 路径前缀:`/sl/projection/map-edit`YARP → SimpleLite `/projection/map-edit`)。
* 与 Simple3 `MapEditApiController` 对应的前端胶水。
* 路径前缀:`/sl/projection/map-edit`YARP → Simple3 `/projection/map-edit`)。
*
* 也覆盖 AI 服务配置 `/sl/projection/ai-config`GET / POST),由 AiConfigController 提供。
*
@@ -205,7 +205,7 @@ export const mapEditApi = {
unwrap<{ count: number; results: unknown[] }>(http.post(`${BASE}/objects/batch`, { ops })),
/**
* CAD 相对包围盒对齐(SimpleLite CadAlignService)。
* CAD 相对包围盒对齐(Simple3 CadAlignService)。
* mode: left|right|top|bottom|centerH|centerV|center|distributeH|distributeV
*/
cadAlign: (mode: string, targets: Array<{ kind: string; id: number }>) =>
@@ -264,8 +264,15 @@ export const mapEditApi = {
),
// 拾取 / 仪表盘。snap=false 时落点用原始鼠标坐标(文本/图片/站点);布线取端点默认 true。
pick: (opts?: { snap?: boolean }) =>
unwrap<PickResult>(http.post(`${BASE}/pick`, { snap: opts?.snap ?? true })),
pick: (opts?: { snap?: boolean; signal?: AbortSignal }) =>
unwrap<PickResult>(http.post(
`${BASE}/pick`,
{ snap: opts?.snap ?? true },
{ timeout: 0, signal: opts?.signal }
)),
cancelPick: () =>
unwrap<{ cancelled: boolean }>(http.post(`${BASE}/pick/cancel`)),
dashboardSummary: () =>
unwrap<DashboardSummary>(http.get(`${BASE}/dashboard/summary`)),
@@ -300,9 +307,9 @@ export const mapEditApi = {
}>(http.get(`${BASE}/project/browse`, { params: dir ? { dir } : {} })),
/**
* 在 SimpleLite 桌面进程上弹 Windows 原生「打开文件」对话框,
* 在 Simple3 桌面进程上弹 Windows 原生「打开文件」对话框,
* 让用户挑一个项目 JSON。返回 { path, cancelled }cancelled=true 时 path 为 null。
* initialDir 默认 SimpleLite 程序工作目录。
* initialDir 默认 Simple3 程序工作目录。
*/
projectNativePickOpen: (initialDir?: string) =>
unwrap<{ path: string | null; cancelled: boolean }>(
@@ -328,7 +335,7 @@ export const mapEditApi = {
/**
* 读取后端「过滤」菜单当前的三组开关。编辑器载入时拉一次,让前端 reactive 状态
* 与 SimpleLite 真实开关一致(避免「前端勾着、后端没改」的偏差)。
* 与 Simple3 真实开关一致(避免「前端勾着、后端没改」的偏差)。
*/
getViewFilter: () => unwrap<ViewFilterSnapshot>(http.get(`${BASE}/view-filter`)),
@@ -348,7 +355,7 @@ export const aiConfigApi = {
// ──────────────────────────────────────────────────────────────────────────
// 地图管理(固定文件夹 + 按名称列表 / 保存 / 删除 / 使用 / 编辑打开)
// 对应 SimpleLite MapEditApiController 的 /map-edit/maps* 接口。
// 对应 Simple3 MapEditApiController 的 /map-edit/maps* 接口。
// ──────────────────────────────────────────────────────────────────────────
export interface MapListItem {
@@ -6,7 +6,7 @@ import type { Mission, MissionStatus } from '@/types/mission'
import { mockSites, mockTracks, mockCars, mockMissions } from '@/mock/server'
import { applyRuntimeEnrichment, deriveCarState } from '@/utils/carRuntime'
/** 设为 true 时使用本地 Mock;默认走 YARP → SimpleLite :8222。
/** 设为 true 时使用本地 Mock;默认走 YARP → Simple3 :8222。
* 与 auth.ts / config.ts / ops.ts 统一走 VITE_USE_MOCK 开关(替代旧的 VITE_PROJECTION_MOCK)。 */
const MOCK = import.meta.env.VITE_USE_MOCK === 'true'
@@ -114,7 +114,7 @@ async function enrichCarsRuntime(cars: Car[]): Promise<Car[]> {
)
}
/** 优先走 SimpleLite /projection/cars502 或空列表时回退 reflection 对象列表(与 3D 场景同源)。 */
/** 优先走 Simple3 /projection/cars502 或空列表时回退 reflection 对象列表(与 3D 场景同源)。 */
export async function listCars(): Promise<Car[]> {
if (MOCK) return mockCars()
try {
@@ -19,10 +19,10 @@ import {
const MOCK = import.meta.env.VITE_USE_MOCK === 'true'
/**
* 与 SimpleLite `ReflectionApiController` 一一对应的前端胶水。
* 路径前缀:`/sl/projection/reflection`(迷榖平台 YARP 反代下游 → SimpleLite EmbedIO)。
* 与 Simple3 `ReflectionApiController` 一一对应的前端胶水。
* 路径前缀:`/sl/projection/reflection`(迷榖平台 YARP 反代下游 → Simple3 EmbedIO)。
*
* 该客户端覆盖了 SimpleLite 主体以及通过 plugins/*.dll 动态加载的 Standard 等
* 该客户端覆盖了 Simple3 主体以及通过 plugins/*.dll 动态加载的 Standard 等
* 插件中所有标注了 `MethodMember` 的方法与所有继承自 Car/Mission/CarProgram/Site/Track
* 的子类型,平台前端可据此动态渲染列表、属性、动作按钮。
*/
@@ -39,7 +39,7 @@ export type ReflectionKind =
| 'map'
| 'special'
| 'script'
// 顶级合成 kind:等于 site + track + special 的并集,由 SimpleLite 后端 /objects/scene 直接返回,
// 顶级合成 kind:等于 site + track + special 的并集,由 Simple3 后端 /objects/scene 直接返回,
// 每行带 subKind 字段,前端 bundle / execute / setField 走对应底层 kind。
| 'scene'
@@ -167,7 +167,7 @@ export interface ScriptExceptionStatusPayload {
// 地图监控可见性配置(与后端 MonitorVisibilityConfig / MonitorVisibilityForKind 对应)
//
// `config` = 管理员勾选的白名单。空数组 = 显示全部;非空 = 仅显示列表中的 key。
// `available` = 当前 SimpleLite 进程里能扫描到的全部可勾选项(基类 + 已加载子类 +
// `available` = 当前 Simple3 进程里能扫描到的全部可勾选项(基类 + 已加载子类 +
// 运行时实例的 Prop.fields / status 反射键)。是 GET 返回的副产物,
// POST 写入时不需要、也不该回传。
// ──────────────────────────────────────────────────────────────────────────
@@ -253,7 +253,7 @@ export function formatReflectionExecuteMessage(
): string {
if (result.returnValue) return `已执行:${result.returnValue}`
if (result.accepted && result.completed === false) {
return `已受理:${label}(后台继续执行,请稍后在 SimpleLite 查看结果)`
return `已受理:${label}(后台继续执行,请稍后在 Simple3 查看结果)`
}
if (result.accepted) return `已执行 ${label}`
return `已执行 ${label}`
@@ -367,7 +367,7 @@ export const reflectionApi = {
: del<{ kind: string; id: number; deleted: boolean }>(`/objects/${kind}/${id}`),
/**
* 触发 SimpleLite 重新扫描 ./plugins 目录、加载新增 dll 并重建 UiDiscoveryCache。
* 触发 Simple3 重新扫描 ./plugins 目录、加载新增 dll 并重建 UiDiscoveryCache。
* 已加载的 dll 不会重复加载。
* 返回:本次发现的 dll 总数、新加载的 assembly 数、当前可创建的 mission/car 类型计数。
*/
@@ -515,7 +515,7 @@ export const reflectionApi = {
return data.data as MonitorConfigSaveBody
},
// 选中同步:让 SimpleLite 3D 场景同步高亮被点击对象
// 选中同步:让 Simple3 3D 场景同步高亮被点击对象
getSelection: () => MOCK
? Promise.resolve<ReflectionSelection>({ kind: null, id: 0, name: '' })
: get<ReflectionSelection>('/selection'),
@@ -685,7 +685,7 @@ export const reflectionApi = {
: post<{ path: string }>('/car-style/save')
}
/** 与 SimpleLite 视口样式对话框 / Configuration.conf.viewport 同步。 */
/** 与 Simple3 视口样式对话框 / Configuration.conf.viewport 同步。 */
export interface ViewportStyleSite {
drawScale: number
dotRadiusNormal: number
@@ -1,14 +1,14 @@
import http from './http'
/**
* 工作区画布工具栏 API(对应 SimpleLite `WorkspaceToolbarApiController`)。
* 工作区画布工具栏 API(对应 Simple3 `WorkspaceToolbarApiController`)。
*
* 历史背景(会话33):原 SimpleLite iframe 内 ImGui 底栏 (`Panel_4` /
* 历史背景(会话33):原 Simple3 iframe 内 ImGui 底栏 (`Panel_4` /
* `WorkspaceBottomBar.DefineForTerminalEmbedMinimal`) 提供 8 个按钮,平台 iframe
* 嵌入时该底栏会盖在画布上影响交互。本会话把这条底栏整体迁到 Vue 端
* `WorkspaceCanvasToolbar.vue` 渲染,状态读写改走该 HTTP API。
*
* 路径前缀:`/sl/projection/toolbar` (Platform.Server YARP → SimpleLite EmbedIO :8222)
* 路径前缀:`/sl/projection/toolbar` (Platform.Server YARP → Simple3 EmbedIO :8222)
*/
const BASE = '/sl/projection/toolbar'
@@ -155,7 +155,7 @@ export const workspaceToolbarApi = {
/**
* 一次性把地图相机定位(居中 + 2D 俯视)到指定车辆,不开启持续跟随。
* 对应 SimpleLite `WorkspaceToolbarApiController.LocateCamera`(与原生「双击车辆行 = 选中+定位」一致)。
* 对应 Simple3 `WorkspaceToolbarApiController.LocateCamera`(与原生「双击车辆行 = 选中+定位」一致)。
*/
locateCamera: (carId: number) =>
unwrap<ToolbarState>(