feat(platform): 部署配置向导 + 地图管理,地图编辑器接入统一存取与 AI 助手
- 配置向导:登录按 deployment 画像引导平台选型(导航方式/模块/场景),未完成则路由守卫强制进入 /wizard;选型驱动菜单按需裁剪,并联动 SimpleLite 写 plugins/active-scenes.json + 透传 --scenes 选择性加载导航场景插件 - 地图管理页:服务器地图列表/使用/重命名/删除、地图合并、多地图连接管理 - 地图编辑器:项目存取改为存入地图管理统一目录(同名替换确认),支持 ?map=/?new= 进入,新增右侧可停靠 AI 助手面板 - 集成 PTL 拣选模块;新增车队分配面板(运维总览/筛选联动) - SimpleLiteBuildSync 同步运行时依赖 DLL;重新构建前端静态资源 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -280,3 +280,136 @@ export const aiConfigApi = {
|
||||
get: () => unwrap<AiConfig>(http.get(`${AI_BASE}/`)),
|
||||
save: (cfg: AiConfig) => unwrap<{ saved: boolean }>(http.post(`${AI_BASE}/`, cfg))
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────────────────────────
|
||||
// 地图管理(固定文件夹 + 按名称列表 / 保存 / 删除 / 使用 / 编辑打开)
|
||||
// 对应 SimpleLite MapEditApiController 的 /map-edit/maps* 接口。
|
||||
// ──────────────────────────────────────────────────────────────────────────
|
||||
|
||||
export interface MapListItem {
|
||||
/** 地图名称(文件名去掉 .json 后缀),列表展示与各操作都以它为标识。 */
|
||||
name: string
|
||||
fileName: string
|
||||
sizeBytes: number
|
||||
modified: string
|
||||
/** 是否为当前项目默认使用的地图(列表高亮)。 */
|
||||
isCurrent: boolean
|
||||
}
|
||||
|
||||
export interface MapListResult {
|
||||
directory: string
|
||||
currentFileName: string | null
|
||||
maps: MapListItem[]
|
||||
}
|
||||
|
||||
export interface MapLoadSummary {
|
||||
name: string
|
||||
fileName: string
|
||||
path: string
|
||||
sites: number
|
||||
tracks: number
|
||||
specials: number
|
||||
missions: number
|
||||
}
|
||||
|
||||
export interface SceneTaskBusyCar {
|
||||
id: number
|
||||
name: string
|
||||
reasons: string[]
|
||||
}
|
||||
|
||||
export interface SceneTaskStatus {
|
||||
hasTask: boolean
|
||||
busyCount: number
|
||||
busyCars: SceneTaskBusyCar[]
|
||||
}
|
||||
|
||||
export interface MapSaveResult {
|
||||
name: string
|
||||
fileName: string
|
||||
path: string
|
||||
savedAt: string
|
||||
}
|
||||
|
||||
/** 保存结果:success 正常返回 data;conflict=true 表示同名地图已存在,调用方应弹「替换」确认。 */
|
||||
export type MapSaveOutcome =
|
||||
| { ok: true; data: MapSaveResult }
|
||||
| { ok: false; conflict: boolean; message: string }
|
||||
|
||||
export interface MapMergeResult {
|
||||
name: string
|
||||
fileName: string
|
||||
path: string
|
||||
/** 底图 = 合并时的「当前使用地图」名。 */
|
||||
baseMap: string
|
||||
/** 合并进来的源地图名(去重、且不含当前地图自身,按叠加顺序)。 */
|
||||
sources: string[]
|
||||
sourceCount: number
|
||||
/** target 与当前地图同名 → 本次合并覆盖了当前地图。 */
|
||||
overwroteCurrent: boolean
|
||||
/** 合并后统计(用于结果提示)。 */
|
||||
sites: number
|
||||
tracks: number
|
||||
specials: number
|
||||
missions: number
|
||||
savedAt: string
|
||||
}
|
||||
|
||||
/** 合并结果:conflict=true 仅表示目标地图同名已存在,调用方应弹「替换」确认后重试。 */
|
||||
export type MapMergeOutcome =
|
||||
| { ok: true; data: MapMergeResult }
|
||||
| { ok: false; conflict: boolean; message: string }
|
||||
|
||||
export const mapsApi = {
|
||||
list: () => unwrap<MapListResult>(http.get(`${BASE}/maps`)),
|
||||
|
||||
sceneTaskStatus: () => unwrap<SceneTaskStatus>(http.get(`${BASE}/maps/scene-task-status`)),
|
||||
|
||||
/**
|
||||
* 保存当前场景为固定文件夹内的地图。overwrite=false 且同名已存在时后端回 409,
|
||||
* 这里翻译为 { ok:false, conflict:true },让调用方弹「是否替换原地图」确认框。
|
||||
*/
|
||||
async save(name: string, overwrite = false): Promise<MapSaveOutcome> {
|
||||
const { data } = await http.post<MapEditEnvelope<MapSaveResult>>(`${BASE}/maps/save`, { name, overwrite })
|
||||
if (data?.success) return { ok: true, data: data.data as MapSaveResult }
|
||||
return { ok: false, conflict: data?.code === 409, message: data?.message ?? '保存失败' }
|
||||
},
|
||||
|
||||
/** 加载指定地图到场景以供编辑(不校验任务、不改当前使用地图)。 */
|
||||
open: (name: string) => unwrap<MapLoadSummary>(http.post(`${BASE}/maps/open`, { name })),
|
||||
|
||||
/**
|
||||
* 设为当前使用地图并加载。后端切换前会校验场景无车辆任务;存在任务回 409,
|
||||
* unwrap 会抛出携带后端友好文案的 Error,调用方 try/catch 提示即可。
|
||||
*/
|
||||
use: (name: string) => unwrap<MapLoadSummary>(http.post(`${BASE}/maps/use`, { name })),
|
||||
|
||||
delete: (name: string) =>
|
||||
unwrap<{ name: string; fileName: string; deleted: boolean }>(
|
||||
http.delete(`${BASE}/maps/${encodeURIComponent(name)}`)
|
||||
),
|
||||
|
||||
/** 重命名 maps 目录下的地图文件(from / to 均为不含扩展名的地图名)。 */
|
||||
rename: (from: string, to: string) =>
|
||||
unwrap<{ from: string; to: string; fileName: string; path: string }>(
|
||||
http.post(`${BASE}/maps/rename`, { from, to })
|
||||
),
|
||||
|
||||
/**
|
||||
* 把选中的地图合并进「当前使用地图」后另存为新地图(语义同桌面端「合并」= SimpleProject.ImportFile)。
|
||||
* sources 为要合并进来的源地图名数组(≥1,当前地图自身会被后端忽略),以「当前使用地图」为底图依次叠加。
|
||||
* target 与当前地图同名 + overwrite 即覆盖当前地图。
|
||||
* 目标同名且 overwrite=false 时后端回 409 → { ok:false, conflict:true },调用方弹「替换」确认;
|
||||
* 当前未设置使用地图(400)/ 场景内有车辆任务(409)时 message 不含「已存在」,conflict=false,调用方直接提示。
|
||||
*/
|
||||
async merge(sources: string[], target: string, overwrite = false): Promise<MapMergeOutcome> {
|
||||
const { data } = await http.post<MapEditEnvelope<MapMergeResult>>(`${BASE}/maps/merge`, {
|
||||
sources,
|
||||
target,
|
||||
overwrite
|
||||
})
|
||||
if (data?.success) return { ok: true, data: data.data as MapMergeResult }
|
||||
const conflict = data?.code === 409 && (data?.message ?? '').includes('已存在')
|
||||
return { ok: false, conflict, message: data?.message ?? '合并失败' }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user