feat: add selectable demo flow tasks
This commit is contained in:
120
server/demoFlow.ts
Normal file
120
server/demoFlow.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
import type {
|
||||
DemoInspectionObject,
|
||||
PluginDemoTask,
|
||||
PluginManifest,
|
||||
} from './plugins/types.js';
|
||||
|
||||
export interface DemoTaskCatalogItem extends PluginDemoTask {
|
||||
pluginId: string;
|
||||
pluginName: string;
|
||||
enabled: boolean;
|
||||
disabledReason?: string;
|
||||
}
|
||||
|
||||
export interface DemoTaskCatalog {
|
||||
inspectionObject: DemoInspectionObject | 'unknown';
|
||||
inspectionObjectName?: string;
|
||||
total: number;
|
||||
items: DemoTaskCatalogItem[];
|
||||
}
|
||||
|
||||
export interface DemoSelectedPluginJob {
|
||||
pluginId: string;
|
||||
taskNos: number[];
|
||||
params: Record<string, unknown>;
|
||||
}
|
||||
|
||||
function disabledReasonFor(
|
||||
task: PluginDemoTask,
|
||||
inspectionObject: DemoInspectionObject | 'unknown',
|
||||
inspectionObjectName?: string,
|
||||
): string | undefined {
|
||||
if (!task.inspectionObjects?.length) return undefined;
|
||||
if (inspectionObject === 'unknown') {
|
||||
return inspectionObjectName
|
||||
? `检测对象“${inspectionObjectName}”尚未配置任务适用规则`
|
||||
: '当前任务尚未确认头车或中车检测对象';
|
||||
}
|
||||
if (!task.inspectionObjects.includes(inspectionObject)) {
|
||||
return `不适用于当前${inspectionObject === 'head' ? '头车' : '中车'}检测对象`;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/** 从插件 manifest 构建服务端权威任务目录。 */
|
||||
export function buildDemoTaskCatalog(
|
||||
manifests: readonly PluginManifest[],
|
||||
inspectionObject: DemoInspectionObject | 'unknown',
|
||||
inspectionObjectName?: string,
|
||||
): DemoTaskCatalog {
|
||||
const items: DemoTaskCatalogItem[] = [];
|
||||
const claimedTaskNos = new Map<number, string>();
|
||||
|
||||
for (const manifest of manifests) {
|
||||
for (const task of manifest.demoTasks ?? []) {
|
||||
const previousPlugin = claimedTaskNos.get(task.taskNo);
|
||||
if (previousPlugin) {
|
||||
throw new Error(`演示任务 ${task.taskNo} 被插件 ${previousPlugin} 与 ${manifest.id} 重复声明`);
|
||||
}
|
||||
claimedTaskNos.set(task.taskNo, manifest.id);
|
||||
const disabledReason = disabledReasonFor(task, inspectionObject, inspectionObjectName);
|
||||
items.push({
|
||||
...task,
|
||||
pluginId: manifest.id,
|
||||
pluginName: manifest.name,
|
||||
enabled: disabledReason == null,
|
||||
...(disabledReason ? { disabledReason } : {}),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
items.sort((a, b) => a.taskNo - b.taskNo);
|
||||
return {
|
||||
inspectionObject,
|
||||
...(inspectionObjectName ? { inspectionObjectName } : {}),
|
||||
total: items.filter((item) => item.enabled).length,
|
||||
items,
|
||||
};
|
||||
}
|
||||
|
||||
/** 校验所选任务并转换为最小插件作业集合。 */
|
||||
export function resolveSelectedDemoJobs(
|
||||
manifests: readonly PluginManifest[],
|
||||
catalog: DemoTaskCatalog,
|
||||
requestedTaskNos: readonly number[],
|
||||
): { taskNos: number[]; jobs: DemoSelectedPluginJob[] } {
|
||||
const taskNos = Array.from(new Set(requestedTaskNos)).sort((a, b) => a - b);
|
||||
if (taskNos.length === 0) throw new Error('请至少选择一个任务');
|
||||
|
||||
const itemByTaskNo = new Map(catalog.items.map((item) => [item.taskNo, item]));
|
||||
for (const taskNo of taskNos) {
|
||||
const item = itemByTaskNo.get(taskNo);
|
||||
if (!item) throw new Error(`任务 ${taskNo} 不存在或当前算法未提供`);
|
||||
if (!item.enabled) throw new Error(`任务 ${taskNo} 当前不可执行:${item.disabledReason ?? '运行条件不满足'}`);
|
||||
}
|
||||
|
||||
const taskNosByPlugin = new Map<string, number[]>();
|
||||
for (const taskNo of taskNos) {
|
||||
const pluginId = itemByTaskNo.get(taskNo)!.pluginId;
|
||||
const pluginTaskNos = taskNosByPlugin.get(pluginId) ?? [];
|
||||
pluginTaskNos.push(taskNo);
|
||||
taskNosByPlugin.set(pluginId, pluginTaskNos);
|
||||
}
|
||||
|
||||
const manifestById = new Map(manifests.map((manifest) => [manifest.id, manifest]));
|
||||
const jobs: DemoSelectedPluginJob[] = [];
|
||||
for (const [pluginId, pluginTaskNos] of Array.from(taskNosByPlugin.entries())) {
|
||||
const manifest = manifestById.get(pluginId);
|
||||
if (!manifest) throw new Error(`未注册的算法插件:${pluginId}`);
|
||||
if (manifest.demoSelection?.kind !== 'task-nos' || !manifest.demoSelection.param) {
|
||||
throw new Error(`算法插件 ${pluginId} 未配置任务选择执行方式`);
|
||||
}
|
||||
jobs.push({
|
||||
pluginId,
|
||||
taskNos: pluginTaskNos,
|
||||
params: { [manifest.demoSelection.param]: pluginTaskNos },
|
||||
});
|
||||
}
|
||||
|
||||
return { taskNos, jobs };
|
||||
}
|
||||
Reference in New Issue
Block a user