feat: 迁入 MiGu.Server、平台前端与车辆列表 reflection 回退
从 Simple-FR 拆出 Platform.Server 并重命名为 MiGu.Server;frontends 源码与构建脚本迁入本仓库。地图监控在 projection/cars 失败或为空时回退 reflection 车辆列表;Simple 仓库已移除旧 Platform.Server。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { mapEditApi } from '@/api/mapEdit'
|
||||
import { reflectionApi, type ReflectionKind, type ReflectionMethod } from '@/api/reflection'
|
||||
|
||||
/** 需在 Web 端先选站点再执行的动作(后端方法内部依赖 SimpleUI.GetPoint,iframe 下不可靠)。 */
|
||||
const SITE_PICK_METHOD_NAMES = new Set(['Goto', 'GotoSite'])
|
||||
const SITE_PICK_LABEL_HINTS = ['去某地', '前往站点']
|
||||
|
||||
export function methodNeedsSitePick(m: ReflectionMethod): boolean {
|
||||
if (m.params?.length) return false
|
||||
if (SITE_PICK_METHOD_NAMES.has(m.methodName)) return true
|
||||
const label = m.label ?? ''
|
||||
return SITE_PICK_LABEL_HINTS.some((h) => label.includes(h))
|
||||
}
|
||||
|
||||
export interface SitePickOption {
|
||||
id: number
|
||||
name: string
|
||||
label: string
|
||||
}
|
||||
|
||||
export async function loadSitePickOptions(): Promise<SitePickOption[]> {
|
||||
const rows = await reflectionApi.listObjects('site')
|
||||
return rows
|
||||
.map((s) => ({
|
||||
id: s.id,
|
||||
name: s.name,
|
||||
label: `#${s.id} ${s.name || '站点'}`
|
||||
}))
|
||||
.sort((a, b) => a.id - b.id)
|
||||
}
|
||||
|
||||
/** 在地图上拾取目标站点(调用 SimpleLite pick 会话)。 */
|
||||
export async function pickTargetSiteOnMap(): Promise<number | null> {
|
||||
try {
|
||||
ElMessage.info({ message: '请在 3D 地图上点击目标站点附近', duration: 4000 })
|
||||
const r = await mapEditApi.pick()
|
||||
if (r.siteId == null || r.siteId < 0) {
|
||||
ElMessage.warning('未识别到附近站点,请靠近站点再点击')
|
||||
return null
|
||||
}
|
||||
return r.siteId
|
||||
} catch (e) {
|
||||
if (e instanceof Error && /取消|cancel|499/i.test(e.message)) return null
|
||||
ElMessage.error(`地图拾取失败:${e instanceof Error ? e.message : String(e)}`)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export async function executeCarGotoSite(carId: number, siteId: number): Promise<boolean> {
|
||||
try {
|
||||
const r = await reflectionApi.gotoCarSite(carId, siteId)
|
||||
ElMessage.success(r.message || `已下发前往站点 #${siteId}`)
|
||||
return true
|
||||
} catch (e) {
|
||||
ElMessage.error(`前往站点失败:${e instanceof Error ? e.message : String(e)}`)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export async function executeReflectionMethod(
|
||||
kind: ReflectionKind,
|
||||
objectId: number,
|
||||
m: ReflectionMethod
|
||||
): Promise<boolean> {
|
||||
const label = m.label || m.methodName
|
||||
const params: Record<string, string> = {}
|
||||
for (const p of m.params) {
|
||||
try {
|
||||
const { value } = await ElMessageBox.prompt(
|
||||
`参数 ${p.name}(${p.typeName})`,
|
||||
label,
|
||||
{
|
||||
inputValue: p.defaultValue ?? '',
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消'
|
||||
}
|
||||
)
|
||||
params[p.name] = value ?? ''
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const r = await reflectionApi.execute(kind, objectId, m.methodName, params)
|
||||
ElMessage.success(r.returnValue ? `已执行:${r.returnValue}` : `已执行 ${label}`)
|
||||
return true
|
||||
} catch (e) {
|
||||
ElMessage.error(`执行失败:${e instanceof Error ? e.message : String(e)}`)
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
import { reflectionApi, emptyMonitorVisibilityMap, type MonitorVisibilityMap } from '@/api/reflection'
|
||||
import { DEFAULT_OPS } from '@/mock/data/configs'
|
||||
import type { MonitorOpsPolicy, OpsConfig } from '@/types/config'
|
||||
|
||||
export function defaultMonitorPolicy(): MonitorOpsPolicy {
|
||||
return JSON.parse(JSON.stringify(DEFAULT_OPS.monitor)) as MonitorOpsPolicy
|
||||
}
|
||||
|
||||
export function normalizeOpsConfig(raw?: Partial<OpsConfig> | null): OpsConfig {
|
||||
const base = JSON.parse(JSON.stringify(DEFAULT_OPS)) as OpsConfig
|
||||
if (!raw) return base
|
||||
const monitor = {
|
||||
...defaultMonitorPolicy(),
|
||||
...(raw.monitor ?? {}),
|
||||
car: { ...defaultMonitorPolicy().car, ...(raw.monitor?.car ?? {}) },
|
||||
site: { ...defaultMonitorPolicy().site, ...(raw.monitor?.site ?? {}) },
|
||||
track: { ...defaultMonitorPolicy().track, ...(raw.monitor?.track ?? {}) },
|
||||
carActionByType: { ...(raw.monitor?.carActionByType ?? {}) }
|
||||
}
|
||||
return {
|
||||
...base,
|
||||
...raw,
|
||||
playback: { ...base.playback, ...(raw.playback ?? {}) },
|
||||
logRetention: { ...base.logRetention, ...(raw.logRetention ?? {}) },
|
||||
version: { ...base.version, ...(raw.version ?? {}) },
|
||||
monitor
|
||||
}
|
||||
}
|
||||
|
||||
type MonitorConfigRoot = MonitorVisibilityMap & { carActionByType?: Record<string, string[]> }
|
||||
|
||||
function pickMonitorRoot(cfg: MonitorConfigRoot) {
|
||||
return {
|
||||
carActionByType: { ...(cfg.carActionByType ?? {}) },
|
||||
siteActionKeys: [...(cfg.site?.methods ?? [])],
|
||||
trackActionKeys: [...(cfg.track?.methods ?? [])]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 SimpleLite simple.json 加载地图监控配置(运行时唯一可信源)。
|
||||
* Platform ops 里的 monitor 仅作备份;以 SimpleLite 为准覆盖表单。
|
||||
*/
|
||||
export async function loadMonitorSettingsIntoOps(payload: OpsConfig): Promise<OpsConfig> {
|
||||
const next = normalizeOpsConfig(payload)
|
||||
try {
|
||||
const mc = await reflectionApi.getMonitorConfig()
|
||||
const picked = pickMonitorRoot(mc.config as MonitorConfigRoot)
|
||||
next.monitor.carActionByType = picked.carActionByType
|
||||
next.monitor.site.actionKeys = picked.siteActionKeys
|
||||
next.monitor.track.actionKeys = picked.trackActionKeys
|
||||
} catch {
|
||||
// SimpleLite 未连接:退回 Platform payload 中已有的 monitor(若有)
|
||||
}
|
||||
return next
|
||||
}
|
||||
|
||||
/**
|
||||
* 将运营维护表单中的地图监控配置写入 SimpleLite(simple.json)。
|
||||
* 保留「地图监控配置」页面对 fields/status 的既有设置,只更新动作相关字段。
|
||||
*/
|
||||
export async function saveMonitorSettingsFromOps(payload: OpsConfig): Promise<void> {
|
||||
const monitor = normalizeOpsConfig(payload).monitor
|
||||
let current: MonitorConfigRoot = emptyMonitorVisibilityMap()
|
||||
try {
|
||||
const mc = await reflectionApi.getMonitorConfig()
|
||||
current = mc.config as MonitorConfigRoot
|
||||
} catch {
|
||||
// 无现有配置时用空壳,仍可写入动作白名单
|
||||
}
|
||||
|
||||
await reflectionApi.saveMonitorConfig({
|
||||
car: {
|
||||
fields: [...(current.car?.fields ?? [])],
|
||||
status: [...(current.car?.status ?? [])],
|
||||
methods: [...(current.car?.methods ?? [])]
|
||||
},
|
||||
site: {
|
||||
fields: [...(current.site?.fields ?? [])],
|
||||
status: [...(current.site?.status ?? [])],
|
||||
methods: [...monitor.site.actionKeys]
|
||||
},
|
||||
track: {
|
||||
fields: [...(current.track?.fields ?? [])],
|
||||
status: [...(current.track?.status ?? [])],
|
||||
methods: [...monitor.track.actionKeys]
|
||||
},
|
||||
carActionByType: { ...monitor.carActionByType }
|
||||
})
|
||||
}
|
||||
|
||||
/** @deprecated 使用 loadMonitorSettingsIntoOps */
|
||||
export const mergeMonitorFromSimpleLite = loadMonitorSettingsIntoOps
|
||||
|
||||
/** @deprecated 使用 saveMonitorSettingsFromOps */
|
||||
export const syncOpsMonitorToSimpleLite = saveMonitorSettingsFromOps
|
||||
Reference in New Issue
Block a user