OHIF WorkflowStepService:为 DICOM 影像应用编排多步骤临床工作流
OHIF WorkflowStepService为 DICOM 影像应用编排多步骤临床工作流【免费下载链接】ViewersOHIF zero-footprint DICOM viewer and oncology specific Lesion Tracker, plus shared extension packages项目地址: https://gitcode.com/GitHub_Trending/vi/Viewers在 OHIF 中复杂的多模态影像任务如预临床 4D PET/CT 的配准、ROI 定量、动力学分析往往需要用户按既定顺序逐阶段操作。WorkflowStepService 正是为此设计它允许把一个模式Mode的工作流拆分成若干“步骤”每个步骤独立配置挂片协议Hanging Protocol、面板布局、工具栏按钮与进入/退出回调并随用户切换步骤动态驱动查看器界面。读完本文你可以掌握工作流步骤的完整结构定义、在 Mode 中的集成时机、步骤切换时的底层执行顺序以及配套的 ProgressDropdown 导航 UI 的实现原理。什么是 WorkflowStepServiceWorkflowStepService 是 OHIF 核心平台提供的一个服务其源码位于 WorkflowStepsService.ts并通过 services/index.ts 注册进服务集合REGISTRATION.name为workflowStepsService见 appInit.js 的服务列表类型声明挂载在 Services.ts 与 AppTypes.ts 上因此任何 Mode 中都可以从servicesManager.services.workflowStepsService拿到它。从源码结构看该服务继承自 PubSubService对外暴露两个事件L5-L8事件常量事件名触发时机EVENTS.ACTIVE_STEP_CHANGEDevent::workflowStepsService:activateStepChanged激活的步骤切换成功后广播载荷为{ activeWorkflowStep }EVENTS.STEPS_CHANGEDevent::workflowStepsService:stepsChanged步骤列表发生新增后广播这两个事件是 UI 组件如进度下拉框与核心状态保持同步的关键通道。工作流步骤的解剖结构Anatomy of a Workflow Step每个工作流步骤由若干组件/属性共同定义用于定制该阶段的应用界面、可用工具与行为。源码中的 TypeScript 类型WorkflowStepL62-L81给出了完整的字段约束字段类型必填作用idstring是步骤的唯一标识重复注册会直接抛出Duplicated workflow step id错误L111-L130namestring是人类可读的名称显示在界面中帮助用户理解当前阶段hangingProtocol{ protocolId, stageId? }否指定本步骤使用的挂片协议与 stage确保显示正确的数据视口与呈现方式layout{ panels: { left?, right? }, options? }否定义左右两侧面板的组成与可见性选项如leftPanelClosed、rightPanelClosedtoolbarButtons{ buttonSection, buttons: string[] }[]否本步骤工具栏可用的按钮。注意按钮必须已事先通过toolbarService注册这里只是引用按钮 idonEnter函数或{ commandName, options }[]否进入步骤时执行的回调或命令onExit函数或{ commandName, options }[]否离开步骤时执行的回调或命令infostring否附加说明在 UI 中作为 tooltip 显示需要注意toolbarButtons的写法源码_updateToolBarL132-L142会将单个对象或数组统一归一化为数组然后对每个{ buttonSection, buttons }先clearButtonSection再updateSection即切换步骤会清空并重建对应按钮分区保证不同步骤呈现完全不同的工具集。一个完整的步骤配置示例以下示例展示了 pre-clinical 4D 工作流的步骤定义与仓库中 getWorkflowSettings.ts 的实际用法一致const dynamicVolume { sopClassHandler: ohif/extension-cornerstone-dynamic-volume.sopClassHandlerModule.dynamic-volume, leftPanel: ohif/extension-cornerstone-dynamic-volume.panelModule.dynamic-volume, toolBox: ohif/extension-cornerstone-dynamic-volume.panelModule.dynamic-toolbox, export: ohif/extension-cornerstone-dynamic-volume.panelModule.dynamic-export, } const cs3d { segmentation: ohif/extension-cornerstone-dicom-seg.panelModule.panelSegmentation, } const steps [ { id: dataPreparation, name: Data Preparation, layout: { panels: { left: [dynamicVolume.leftPanel], }, }, toolbarButtons: { buttonSection: primary, buttons: [MeasurementTools, Zoom, WindowLevel, Crosshairs, Pan], }, hangingProtocol: { protocolId: default4D, stageId: dataPreparation, }, info: In the Data Preparation step..., }, { id: roiQuantification, name: ROI Quantification, layout: { panels: { left: [dynamicVolume.leftPanel], right: [ [dynamicVolume.toolBox, cs3d.segmentation, dynamicVolume.export], ], }, options: { leftPanelClosed: false, rightPanelClosed: false, }, }, toolbarButtons: [ { buttonSection: primary, buttons: [ MeasurementTools, Zoom, WindowLevel, Crosshairs, Pan, ], }, { buttonSection: dynamic-toolbox, buttons: [BrushTools, RectangleROIStartEndThreshold], }, ], hangingProtocol: { protocolId: default4D, stageId: roiQuantification, }, info: The ROI quantification step ..., }, { id: kineticAnalysis, name: Kinetic Analysis, layout: { panels: { left: [dynamicVolume.leftPanel], right: [], }, }, toolbarButtons: { buttonSection: primary, buttons: [MeasurementTools, Zoom, WindowLevel, Crosshairs, Pan], }, hangingProtocol: { protocolId: default4D, stageId: kineticAnalysis, }, onEnter: [ { commandName: updateSegmentationsChartDisplaySet, options: { servicesManager }, }, ], info: The Kinetic Analysis step ..., }, ]示例中三个步骤分别对应“数据准备 → ROI 定量 → 动力学分析”第二步启用了dynamic-toolbox分区用于分割工具第三步通过onEnter命令在进入时刷新分割结果对应的图表 displaySet。完整的四步配置含registration步骤可参考 getWorkflowSettings.ts。在 Mode 中集成工作流步骤定义好步骤后需要在 Mode 工厂中完成集成。官方文档明确指出这些步骤应当在onSetupRouteComplete中注册而不能在onModeEnter中调用——因为onModeEnter触发时 Mode 尚未完全初始化挂片协议匹配等流程可能还未完成它会依据工作流 stage 设置改写 protocol/stage。仓库中 preclinical-4d 模式 给出了完整示例。Mode 工厂的onSetupRouteComplete回调L127-L131委托给一个初始化函数// modes/preclinical-4d/src/initWorkflowSteps.ts export default function initWorkflowSteps({ servicesManager }: withAppTypes): void { const { workflowStepsService } servicesManager.services; const workflowSettings getWorkflowSettings({ servicesManager }); workflowStepsService.addWorkflowSteps(workflowSettings.steps); workflowStepsService.setActiveWorkflowStep(workflowSettings.steps[0].id); }对应文档中的最简集成形式为onSetupRouteComplete: ({ servicesManager }) { workflowStepsService.addWorkflowSteps(workflowSettings.steps); workflowStepsService.setActiveWorkflowStep(workflowSettings.steps[0].id); },这里有两个值得注意的事实addWorkflowSteps幂等性检查id重复会抛出异常全部新增成功且至少有一个新步骤时广播STEPS_CHANGED事件。Mode 生命周期中的重置WorkflowStepsService实现了onModeEnter()L231-L233内部调用reset()清空步骤列表与激活步骤。也就是说每次进入 Mode 时状态都是干净的随后由onSetupRouteComplete重新注册——这正是“不能在onModeEnter里注册步骤、要等路由完成后再注册”的生命周期约束的由来。此外preclinical-4d 模式还通过hangingProtocol: default4Dindex.tsx L200声明了默认协议步骤配置中的protocolId即引用它。步骤切换时的底层执行顺序理解setActiveWorkflowStep(workflowStepId)L194-L224的内部时序是掌握该服务行为的关键。源码中的执行顺序为快速返回目标 id 与当前激活步骤相同则不做任何事查找步骤找不到对应 id 时抛出Invalid workflowStepId (...)执行旧步骤的onExit回调若存在激活步骤执行新步骤的onEnter回调——源码注释特别强调这一步必须先于挂片协议更新执行因为某些 displaySet例如把分割转换为图表 displaySet需要在切换到新的 HP stage 之前先创建出来更新工具栏_updateToolBar按toolbarButtons逐分区清空并重建按钮更新面板_updatePanels调用panelService.setPanels(panels, options)把layout.options如leftPanelClosed一并传入L144-L153更新挂片协议_updateHangingProtocol通过commandsManager.runCommand(setHangingProtocol, { protocolId, stageId, stageIndex })切换显示L155-L167广播ACTIVE_STEP_CHANGED事件载荷包含新的activeWorkflowStep。回调本身由_invokeCallbacksL169-L192统一处理它兼容两种形态——直接的函数或{ commandName, options }形式的命令对象后者会被包装成commandsManager.runCommand的调用并且非数组的单回调会被归一化为数组后逐个执行。ProgressDropdown步骤导航 UIOHIF 提供了一个简单的下拉组件用于在步骤间导航。集成方式为向工具栏注册一个按钮并放入secondary分区toolbarService.addButtons([ { id: ProgressDropdown, uiType: ohif.progressDropdown, }, ]) toolbarService.createButtonSection(secondary, [ProgressDropdown]);在 preclinical-4d 模式中ProgressDropdown按钮定义在 toolbarButtons.tsx 中Mode 的onModeEnter通过toolbarService.updateSection(toolbarService.sections.secondary, [ProgressDropdown])将其放入 secondary 位置index.tsx L59。如果想把进度下拉框放到其他位置可以使用 Toolbar 模块的 Toolbox 组件创建自定义按钮分区详见 Toolbar 模块文档。从源码结构看uiType: ohif.progressDropdown背后由 ProgressDropdownWithService.tsx 实现它的工作方式包括将workflowStepsService.workflowSteps映射为下拉选项其中每个步骤的name作为 label、id作为 value、info字段作为该选项的 tooltip 提示这正是步骤info字段在 UI 中的落点用户选中某个步骤后调用workflowStepsService.setActiveWorkflowStep(selectedOption.value)触发整套界面更新并把该步骤及其之前的步骤标记为completed源码注释中说明“步骤完成状态目前由导航行为推导尚非基于用户完成特定动作判定”组件订阅STEPS_CHANGED与ACTIVE_STEP_CHANGED两个事件在服务端状态变化时刷新本地下拉选项与选中项实现 UI 与服务状态的双向同步L79-L95。小结与参考WorkflowStepService 把“挂片协议 stage、面板布局、工具栏按钮、进入/退出回调”四个维度的配置收敛到单一的步骤对象中并通过onSetupRouteComplete注册、setActiveWorkflowStep驱动的时序化更新机制使查看器能够随着临床工作流的推进自动变形。编写新的分步工作流时建议按以下清单落地在扩展/Mode 中预先用toolbarService注册所有按钮定义步骤里只引用 id定义步骤数组id全局唯一hangingProtocol.stageId与协议中的 stage 对齐在 Mode 工厂的onSetupRouteComplete中addWorkflowStepssetActiveWorkflowStep激活首步骤注册ProgressDropdown按钮并放入目标工具栏分区供用户导航。关键文件索引文件说明WorkflowStepsService.ts服务核心实现事件、WorkflowStep类型、addWorkflowSteps、setActiveWorkflowStepservices/index.ts服务注册入口index.tsxpreclinical-4d 模式Mode 工厂与onSetupRouteComplete集成getWorkflowSettings.ts四步工作流的完整步骤配置initWorkflowSteps.ts步骤注册的最简封装ProgressDropdownWithService.tsx步骤导航下拉框组件实现Toolbar 模块文档自定义按钮分区Toolbox的进一步配置【免费下载链接】ViewersOHIF zero-footprint DICOM viewer and oncology specific Lesion Tracker, plus shared extension packages项目地址: https://gitcode.com/GitHub_Trending/vi/Viewers创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考